# Objective
Getting access to the original target of an entity-event is really
helpful when working with bubbled / propagated events.
`bevy_picking` special-cases this, but users have requested this for all
sorts of bubbled events.
The existing naming convention was also very confusing. Fixes
https://github.com/bevyengine/bevy/issues/17112, but also see #18982.
## Solution
1. Rename `ObserverTrigger::target` -> `current_target`.
1. Store `original_target: Option<Entity>` in `ObserverTrigger`.
1. Wire it up so this field gets set correctly.
1. Remove the `target` field on the `Pointer` events from
`bevy_picking`.
Closes https://github.com/bevyengine/bevy/pull/18710, which attempted
the same thing. Thanks @emfax!
## Testing
I've modified an existing test to check that the entities returned
during event bubbling / propagation are correct.
## Notes to reviewers
It's a little weird / sad that you can no longer access this infromation
via the buffered events for `Pointer`. That said, you already couldn't
access any bubbled target. We should probably remove the `BufferedEvent`
form of `Pointer` to reduce confusion and overhead, but I didn't want to
do so here.
Observer events can be trivially converted into buffered events (write
an observer with an EventWriter), and I suspect that that is the better
migration if you want the controllable timing or performance
characteristics of buffered events for your specific use case.
## Future work
It would be nice to not store this data at all (and not expose any
methods) if propagation was disabled. That involves more trait
shuffling, and I don't think we should do it here for reviewability.
---------
Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
# Objective
- Try to make more of `bevy_color` const now that we have
const_float_arithmetic.
## Solution
Fail abjectly, because of our heavy use of traits.
I did find these functions though, so you can have a PR 🙃
# Objective
- `remove_child` was mentioned missing in #19556 and I realized that
`insert_child` was also missing.
- Removes the need to wrap a single entity with `&[]` with
`remove_children` and `insert_children`
- Would have also added `despawn_children` but #19283 does so.
## Solution
- Simple wrapper around `remove_related`
## Testing
- Added `insert_child` and `remove_child` tests analgous to
`insert_children` and `remove_children` and then ran `cargo run -p ci --
test`
# Objective
As someone who is currently learning Bevy, I found the implementation of
the ambient light in the 3d/lighting.rs example unsatisfactory.
## Solution
- I adjusted the brightness of the ambient light in the scene to 200
(where the default is 80). It was previously 0.02, a value so low it has
no noticeable effect.
- I added a keybind (space bar) to toggle the ambient light, allowing
users to see the difference it makes. I also added text showing the
state of the ambient light (on, off) and text showing the keybind.
I'm very new to Bevy and Rust, so apologies if any of this code is not
up to scratch.
## Testing
I checked all the text still updates correctly and all keybinds still
work. In my testing, it looks to work okay.
I'd appreciate others testing too, just to make sure.
---
## Showcase
<details>
<summary>Click to view showcase</summary>
<img width="960" alt="Screenshot (11)"
src="https://github.com/user-attachments/assets/916e569e-cd49-43fd-b81d-aae600890cd3"
/>
<img width="959" alt="Screenshot (12)"
src="https://github.com/user-attachments/assets/0e16bb3a-c38a-4a8d-8248-edf3b820d238"
/>
</details>
# Objective
Closes#19564.
The current `Event` trait looks like this:
```rust
pub trait Event: Send + Sync + 'static {
type Traversal: Traversal<Self>;
const AUTO_PROPAGATE: bool = false;
fn register_component_id(world: &mut World) -> ComponentId { ... }
fn component_id(world: &World) -> Option<ComponentId> { ... }
}
```
The `Event` trait is used by both buffered events
(`EventReader`/`EventWriter`) and observer events. If they are observer
events, they can optionally be targeted at specific `Entity`s or
`ComponentId`s, and can even be propagated to other entities.
However, there has long been a desire to split the trait semantically
for a variety of reasons, see #14843, #14272, and #16031 for discussion.
Some reasons include:
- It's very uncommon to use a single event type as both a buffered event
and targeted observer event. They are used differently and tend to have
distinct semantics.
- A common footgun is using buffered events with observers or event
readers with observer events, as there is no type-level error that
prevents this kind of misuse.
- #19440 made `Trigger::target` return an `Option<Entity>`. This
*seriously* hurts ergonomics for the general case of entity observers,
as you need to `.unwrap()` each time. If we could statically determine
whether the event is expected to have an entity target, this would be
unnecessary.
There's really two main ways that we can categorize events: push vs.
pull (i.e. "observer event" vs. "buffered event") and global vs.
targeted:
| | Push | Pull |
| ------------ | --------------- | --------------------------- |
| **Global** | Global observer | `EventReader`/`EventWriter` |
| **Targeted** | Entity observer | - |
There are many ways to approach this, each with their tradeoffs.
Ultimately, we kind of want to split events both ways:
- A type-level distinction between observer events and buffered events,
to prevent people from using the wrong kind of event in APIs
- A statically designated entity target for observer events to avoid
accidentally using untargeted events for targeted APIs
This PR achieves these goals by splitting event traits into `Event`,
`EntityEvent`, and `BufferedEvent`, with `Event` being the shared trait
implemented by all events.
## `Event`, `EntityEvent`, and `BufferedEvent`
`Event` is now a very simple trait shared by all events.
```rust
pub trait Event: Send + Sync + 'static {
// Required for observer APIs
fn register_component_id(world: &mut World) -> ComponentId { ... }
fn component_id(world: &World) -> Option<ComponentId> { ... }
}
```
You can call `trigger` for *any* event, and use a global observer for
listening to the event.
```rust
#[derive(Event)]
struct Speak {
message: String,
}
// ...
app.add_observer(|trigger: On<Speak>| {
println!("{}", trigger.message);
});
// ...
commands.trigger(Speak {
message: "Y'all like these reworked events?".to_string(),
});
```
To allow an event to be targeted at entities and even propagated
further, you can additionally implement the `EntityEvent` trait:
```rust
pub trait EntityEvent: Event {
type Traversal: Traversal<Self>;
const AUTO_PROPAGATE: bool = false;
}
```
This lets you call `trigger_targets`, and to use targeted observer APIs
like `EntityCommands::observe`:
```rust
#[derive(Event, EntityEvent)]
#[entity_event(traversal = &'static ChildOf, auto_propagate)]
struct Damage {
amount: f32,
}
// ...
let enemy = commands.spawn((Enemy, Health(100.0))).id();
// Spawn some armor as a child of the enemy entity.
// When the armor takes damage, it will bubble the event up to the enemy.
let armor_piece = commands
.spawn((ArmorPiece, Health(25.0), ChildOf(enemy)))
.observe(|trigger: On<Damage>, mut query: Query<&mut Health>| {
// Note: `On::target` only exists because this is an `EntityEvent`.
let mut health = query.get(trigger.target()).unwrap();
health.0 -= trigger.amount();
});
commands.trigger_targets(Damage { amount: 10.0 }, armor_piece);
```
> [!NOTE]
> You *can* still also trigger an `EntityEvent` without targets using
`trigger`. We probably *could* make this an either-or thing, but I'm not
sure that's actually desirable.
To allow an event to be used with the buffered API, you can implement
`BufferedEvent`:
```rust
pub trait BufferedEvent: Event {}
```
The event can then be used with `EventReader`/`EventWriter`:
```rust
#[derive(Event, BufferedEvent)]
struct Message(String);
fn write_hello(mut writer: EventWriter<Message>) {
writer.write(Message("I hope these examples are alright".to_string()));
}
fn read_messages(mut reader: EventReader<Message>) {
// Process all buffered events of type `Message`.
for Message(message) in reader.read() {
println!("{message}");
}
}
```
In summary:
- Need a basic event you can trigger and observe? Derive `Event`!
- Need the event to be targeted at an entity? Derive `EntityEvent`!
- Need the event to be buffered and support the
`EventReader`/`EventWriter` API? Derive `BufferedEvent`!
## Alternatives
I'll now cover some of the alternative approaches I have considered and
briefly explored. I made this section collapsible since it ended up
being quite long :P
<details>
<summary>Expand this to see alternatives</summary>
### 1. Unified `Event` Trait
One option is not to have *three* separate traits (`Event`,
`EntityEvent`, `BufferedEvent`), and to instead just use associated
constants on `Event` to determine whether an event supports targeting
and buffering or not:
```rust
pub trait Event: Send + Sync + 'static {
type Traversal: Traversal<Self>;
const AUTO_PROPAGATE: bool = false;
const TARGETED: bool = false;
const BUFFERED: bool = false;
fn register_component_id(world: &mut World) -> ComponentId { ... }
fn component_id(world: &World) -> Option<ComponentId> { ... }
}
```
Methods can then use bounds like `where E: Event<TARGETED = true>` or
`where E: Event<BUFFERED = true>` to limit APIs to specific kinds of
events.
This would keep everything under one `Event` trait, but I don't think
it's necessarily a good idea. It makes APIs harder to read, and docs
can't easily refer to specific types of events. You can also create
weird invariants: what if you specify `TARGETED = false`, but have
`Traversal` and/or `AUTO_PROPAGATE` enabled?
### 2. `Event` and `Trigger`
Another option is to only split the traits between buffered events and
observer events, since that is the main thing people have been asking
for, and they have the largest API difference.
If we did this, I think we would need to make the terms *clearly*
separate. We can't really use `Event` and `BufferedEvent` as the names,
since it would be strange that `BufferedEvent` doesn't implement
`Event`. Something like `ObserverEvent` and `BufferedEvent` could work,
but it'd be more verbose.
For this approach, I would instead keep `Event` for the current
`EventReader`/`EventWriter` API, and call the observer event a
`Trigger`, since the "trigger" terminology is already used in the
observer context within Bevy (both as a noun and a verb). This is also
what a long [bikeshed on
Discord](https://discord.com/channels/691052431525675048/749335865876021248/1298057661878898791)
seemed to land on at the end of last year.
```rust
// For `EventReader`/`EventWriter`
pub trait Event: Send + Sync + 'static {}
// For observers
pub trait Trigger: Send + Sync + 'static {
type Traversal: Traversal<Self>;
const AUTO_PROPAGATE: bool = false;
const TARGETED: bool = false;
fn register_component_id(world: &mut World) -> ComponentId { ... }
fn component_id(world: &World) -> Option<ComponentId> { ... }
}
```
The problem is that "event" is just a really good term for something
that "happens". Observers are rapidly becoming the more prominent API,
so it'd be weird to give them the `Trigger` name and leave the good
`Event` name for the less common API.
So, even though a split like this seems neat on the surface, I think it
ultimately wouldn't really work. We want to keep the `Event` name for
observer events, and there is no good alternative for the buffered
variant. (`Message` was suggested, but saying stuff like "sends a
collision message" is weird.)
### 3. `GlobalEvent` + `TargetedEvent`
What if instead of focusing on the buffered vs. observed split, we
*only* make a distinction between global and targeted events?
```rust
// A shared event trait to allow global observers to work
pub trait Event: Send + Sync + 'static {
fn register_component_id(world: &mut World) -> ComponentId { ... }
fn component_id(world: &World) -> Option<ComponentId> { ... }
}
// For buffered events and non-targeted observer events
pub trait GlobalEvent: Event {}
// For targeted observer events
pub trait TargetedEvent: Event {
type Traversal: Traversal<Self>;
const AUTO_PROPAGATE: bool = false;
}
```
This is actually the first approach I implemented, and it has the neat
characteristic that you can only use non-targeted APIs like `trigger`
with a `GlobalEvent` and targeted APIs like `trigger_targets` with a
`TargetedEvent`. You have full control over whether the entity should or
should not have a target, as they are fully distinct at the type-level.
However, there's a few problems:
- There is no type-level indication of whether a `GlobalEvent` supports
buffered events or just non-targeted observer events
- An `Event` on its own does literally nothing, it's just a shared trait
required to make global observers accept both non-targeted and targeted
events
- If an event is both a `GlobalEvent` and `TargetedEvent`, global
observers again have ambiguity on whether an event has a target or not,
undermining some of the benefits
- The names are not ideal
### 4. `Event` and `EntityEvent`
We can fix some of the problems of Alternative 3 by accepting that
targeted events can also be used in non-targeted contexts, and simply
having the `Event` and `EntityEvent` traits:
```rust
// For buffered events and non-targeted observer events
pub trait Event: Send + Sync + 'static {
fn register_component_id(world: &mut World) -> ComponentId { ... }
fn component_id(world: &World) -> Option<ComponentId> { ... }
}
// For targeted observer events
pub trait EntityEvent: Event {
type Traversal: Traversal<Self>;
const AUTO_PROPAGATE: bool = false;
}
```
This is essentially identical to this PR, just without a dedicated
`BufferedEvent`. The remaining major "problem" is that there is still
zero type-level indication of whether an `Event` event *actually*
supports the buffered API. This leads us to the solution proposed in
this PR, using `Event`, `EntityEvent`, and `BufferedEvent`.
</details>
## Conclusion
The `Event` + `EntityEvent` + `BufferedEvent` split proposed in this PR
aims to solve all the common problems with Bevy's current event model
while keeping the "weirdness" factor minimal. It splits in terms of both
the push vs. pull *and* global vs. targeted aspects, while maintaining a
shared concept for an "event".
### Why I Like This
- The term "event" remains as a single concept for all the different
kinds of events in Bevy.
- Despite all event types being "events", they use fundamentally
different APIs. Instead of assuming that you can use an event type with
any pattern (when only one is typically supported), you explicitly opt
in to each one with dedicated traits.
- Using separate traits for each type of event helps with documentation
and clearer function signatures.
- I can safely make assumptions on expected usage.
- If I see that an event is an `EntityEvent`, I can assume that I can
use `observe` on it and get targeted events.
- If I see that an event is a `BufferedEvent`, I can assume that I can
use `EventReader` to read events.
- If I see both `EntityEvent` and `BufferedEvent`, I can assume that
both APIs are supported.
In summary: This allows for a unified concept for events, while limiting
the different ways to use them with opt-in traits. No more guess-work
involved when using APIs.
### Problems?
- Because `BufferedEvent` implements `Event` (for more consistent
semantics etc.), you can still use all buffered events for non-targeted
observers. I think this is fine/good. The important part is that if you
see that an event implements `BufferedEvent`, you know that the
`EventReader`/`EventWriter` API should be supported. Whether it *also*
supports other APIs is secondary.
- I currently only support `trigger_targets` for an `EntityEvent`.
However, you can technically target components too, without targeting
any entities. I consider that such a niche and advanced use case that
it's not a huge problem to only support it for `EntityEvent`s, but we
could also split `trigger_targets` into `trigger_entities` and
`trigger_components` if we wanted to (or implement components as
entities :P).
- You can still trigger an `EntityEvent` *without* targets. I consider
this correct, since `Event` implements the non-targeted behavior, and
it'd be weird if implementing another trait *removed* behavior. However,
it does mean that global observers for entity events can technically
return `Entity::PLACEHOLDER` again (since I got rid of the
`Option<Entity>` added in #19440 for ergonomics). I think that's enough
of an edge case that it's not a huge problem, but it is worth keeping in
mind.
- ~~Deriving both `EntityEvent` and `BufferedEvent` for the same type
currently duplicates the `Event` implementation, so you instead need to
manually implement one of them.~~ Changed to always requiring `Event` to
be derived.
## Related Work
There are plans to implement multi-event support for observers,
especially for UI contexts. [Cart's
example](https://github.com/bevyengine/bevy/issues/14649#issuecomment-2960402508)
API looked like this:
```rust
// Truncated for brevity
trigger: Trigger<(
OnAdd<Pressed>,
OnRemove<Pressed>,
OnAdd<InteractionDisabled>,
OnRemove<InteractionDisabled>,
OnInsert<Hovered>,
)>,
```
I believe this shouldn't be in conflict with this PR. If anything, this
PR might *help* achieve the multi-event pattern for entity observers
with fewer footguns: by statically enforcing that all of these events
are `EntityEvent`s in the context of `EntityCommands::observe`, we can
avoid misuse or weird cases where *some* events inside the trigger are
targeted while others are not.
# Objective
- A step towards #19024.
- Allow `ReflectAsset` to work with any `AssetId` not just `Handle`.
- `ReflectAsset::ids()` returns an iterator of `AssetId`s, but then
there's no way to use these ids, since all the other APIs in
`ReflectAsset` require a handle (and we don't have a reflect way to get
the handle).
## Solution
- Replace the `UntypedHandle` argument in `ReflectAsset` methods with
`impl Into<UntypedAssetId>`.
- This matches the regular asset API.
- This allows `ReflectAsset::ids()` to be more useful.
## Testing
- None.
# Objective
The methods and commands `replace_related` and
`replace_related_with_difference` may cause data stored at the
`RelationshipTarget` be lost when all original children are removed
before new children are added.
Part of https://github.com/bevyengine/bevy/issues/19589
## Solution
Fix the issue, either by removing the old children _after_ adding the
new ones and not _before_ (`replace_related_with_difference`) or by
taking the whole `RelationshipTarget` to modify it, not only the inner
collection (`replace_related`).
## Testing
I added a new test asserting the data is kept. I also added a general
test of these methods as they had none previously.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Adds a new component for when you want to run the deferred gbuffer
prepass, but not the lighting pass.
This will be used by bevy_solari in the future, as it'll do it's own
shading pass, but still wants the gbuffer.
# Objective
This is part of the "core widgets" effort: #19236.
## Solution
This PR adds the "core slider" widget to the collection.
## Testing
Tested using examples `core_widgets` and `core_widgets_observers`.
---------
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
# Objective
- Update ron to the latest version.
- This is blocking changes to AnimationGraph (as some valid structs are
not capable of being deserialized).
## Solution
- Bump ron!
## Testing
- The particular issue I was blocked by seems to be resolved!
The documentation states that ClusteredDecal projects in the +Z
direction, but in practice, it projects in the -Z direction, which can
be confusing.
# Objective
Fixes#19612
Follow-up of #19274.
Make the `check_change_tick` methods, of which some are now public, take
`CheckChangeTicks` to make it obvious where this tick comes from, see
other PR.
This also affects the `System` trait, hence the many changed files.
---------
Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com>
# Objective
Reduce memory usage by storing fewer copies of
`FilteredAccessSet<ComponentId>`.
Currently, the `System` trait exposes the `component_access_set` for the
system, which is used by the multi-threaded executor to determine which
systems can run concurrently. But because it is available on the trait,
it needs to be stored for *every* system, even ones that are not run by
the executor! In particular, it is never needed for observers, or for
the inner systems in a `PipeSystem` or `CombinatorSystem`.
## Solution
Instead of exposing the access from a method on `System`, return it from
`System::initialize`. Since it is still needed during scheduling, store
the access alongside the boxed system in the schedule.
That's not quite enough for systems built using `SystemParamBuilder`s,
though. Those calculate the access in `SystemParamBuilder::build`, which
happens earlier than `System::initialize`. To handle those, we separate
`SystemParam::init_state` into `init_state`, which creates the state
value, and `init_access`, which calculates the access. This lets
`System::initialize` call `init_access` on a state that was provided by
the builder.
An additional benefit of that separation is that it removes the need to
duplicate access checks between `SystemParamBuilder::build` and
`SystemParam::init_state`.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- `AutoFocus` component does seem to work with the `set_initial_focus`
that was running in `Startup`.
- If an element is spawn during `PreStartup` or during
`OnEnter(SomeState)` that happens before `Startup`, the focus is
overridden by `set_initial_focus` which sets the focus to the primary
window.
## Solution
- `set_initial_focus` only sets the focus to the `PrimaryWindow` if no
other focus is set.
- *Note*: `cargo test --package bevy_input_focus` was not working, so
some changes are related to that.
## Testing
- `cargo test --package bevy_input_focus`: OK
- `cargo run --package ci`: OK
## Objective
Make it easier to use `IrradianceVolume` with fewer ways to silently
fail. Fix#19614.
## Solution
* Add `#[require(LightProbe)]` to `struct IrradianceVolume`.
* Document this fact.
* Also document the volume being centered on the origin by default (this
was the other thing that was unclear when getting started).
I also looked at the other implementor of `LightProbeComponent`,
`EnvironmentMapLight`, but it has a use which is *not* as a light probe,
so it should not require `LightProbe`.
## Testing
* Confirmed that `examples/3d/irradiance_volumes.rs` still works after
removing `LightProbe`.
* Reviewed generated documentation.
# Objective
- Running `cargo run --package ci` in MacOS does not currently work in
`main`.
- It shows a `error: this lint expectation is unfulfilled`.
- Fixes#19583
## Solution
- Remove an unnecessary `#[expect(clippy::large_enum_variant)]` on a
function.
## Testing
- `cargo run --package ci`: 👍
# Objective
- Add example to `Single` docs, highlighting that you can use methods
and properties directly.
- Fixes#19461
## Solution
- Added example to inline docs of `Single`
## Testing
- `cargo test --doc`
- `cargo doc --open`
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- CI job checking for wasm atomics fails because of an unrelated lint on
nightly rust
- Fixes#19573
## Solution
- Don't deny warning, that's not what this job is checking anyway
# Bevy Solari
<img
src="https://github.com/user-attachments/assets/94061fc8-01cf-4208-b72a-8eecad610d76"
width="100" />
## Preface
- See release notes.
- Please talk to me in #rendering-dev on discord or open a github
discussion if you have questions about the long term plan, and keep
discussion in this PR limited to the contents of the PR :)
## Connections
- Works towards #639, #16408.
- Spawned https://github.com/bevyengine/bevy/issues/18993.
- Need to fix RT stuff in naga_oil first
https://github.com/bevyengine/naga_oil/pull/116.
## This PR
After nearly two years, I've revived the raytraced lighting effort I
first started in https://github.com/bevyengine/bevy/pull/10000.
Unlike that PR, which has realtime techniques, I've limited this PR to:
* `RaytracingScenePlugin` - BLAS and TLAS building, geometry and texture
binding, sampling functions.
* `PathtracingPlugin` - A non-realtime path tracer intended to serve as
a testbed and reference.
## What's implemented?

* BLAS building on mesh load
* Emissive lights
* Directional lights with soft shadows
* Diffuse (lambert, not Bevy's diffuse BRDF) and emissive materials
* A reference path tracer with:
* Antialiasing
* Direct light sampling (next event estimation) with 0/1 MIS weights
* Importance-sampled BRDF bounces
* Russian roulette
## What's _not_ implemented?
* Anything realtime, including a real-time denoiser
* Integration with Bevy's rasterized gbuffer
* Specular materials
* Non-opaque geometry
* Any sort of CPU or GPU optimizations
* BLAS compaction, proper bindless, and further RT APIs are things that
we need wgpu to add
* PointLights, SpotLights, or skyboxes / environment lighting
* Support for materials other than StandardMaterial (and only a subset
of properties are supported)
* Skinned/morphed or otherwise animating/deformed meshes
* Mipmaps
* Adaptive self-intersection ray bias
* A good way for developers to detect whether the user's GPU supports RT
or not, and fallback to baked lighting.
* Documentation and actual finalized APIs (literally everything is
subject to change)
## End-user Usage
* Have a GPU that supports RT with inline ray queries
* Add `SolariPlugin` to your app
* Ensure any `Mesh` asset you want to use for raytracing has
`enable_raytracing: true` (defaults to true), and that it uses the
standard uncompressed position/normal/uv_0/tangent vertex attribute set,
triangle list topology, and 32-bit indices.
* If you don't want to build a BLAS and use the mesh for RT, set
enable_raytracing to false.
* Add the `RaytracingMesh3d` component to your entity (separate from
`Mesh3d` or `MeshletMesh3d`).
## Testing
- Did you test these changes? If so, how?
- Ran the solari example.
- Are there any parts that need more testing?
- Other test scenes probably. Normal mapping would be good to test.
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- See the solari.rs example for how to setup raytracing.
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- Windows 11, NVIDIA RTX 3080.
---------
Co-authored-by: atlv <email@atlasdostal.com>
Co-authored-by: IceSentry <IceSentry@users.noreply.github.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
# Objective
As raised by @Jondolf, this type is `pub`, and useful for various
consumers to ensure cleanup or debugging.
However, it doesn't offer any way to actually view the data.
## Solution
- Add a read-only view of the data.
- Don't add any (easy) way to mutate the data, as this presents a huge
footgun.
- Implement Reflect and register the component so you can see it in
inspectors nicely.
## Objective
- Makes `headless_renderer` example work instead of exiting without
effect.
- Guides users who actually just need
[`Screenshot`](https://docs.rs/bevy/0.16.1/bevy/render/view/window/screenshot/struct.Screenshot.html)
to use that instead.
This PR was inspired by my own efforts to do headless rendering, in
which the complexity of the `headless_renderer` example was a
distraction, and this comment from
https://github.com/bevyengine/bevy/issues/12478#issuecomment-2094925039
:
> The example added in https://github.com/bevyengine/bevy/pull/13006
would benefit from this change: be sure to clean it up when tackling
this work :)
That “cleanup” was not done, and I thought to do it, but it seems to me
that using `Screenshot` (in its current form) in the example would not
be correct, because — if I understand correctly — the example is trying
to, potentially, capture many *consecutive* frames, whereas `Screenshot`
by itself gives no means to capture multiple frames without gaps or
duplicates. But perhaps I am wrong (the code is complex and not clearly
documented), or perhaps that feature isn’t worth preserving. In that
case, let me know and I will revise this PR.
## Solution
- Added `exit_condition: bevy:🪟:ExitCondition::DontExit`
- Added a link to `Screenshot` in the crate documentation.
## Testing
- Ran the example and confirmed that it now writes an image file and
then exits.
# Objective
Currently, the observer API looks like this:
```rust
app.add_observer(|trigger: Trigger<Explode>| {
info!("Entity {} exploded!", trigger.target());
});
```
Future plans for observers also include "multi-event observers" with a
trigger that looks like this (see [Cart's
example](https://github.com/bevyengine/bevy/issues/14649#issuecomment-2960402508)):
```rust
trigger: Trigger<(
OnAdd<Pressed>,
OnRemove<Pressed>,
OnAdd<InteractionDisabled>,
OnRemove<InteractionDisabled>,
OnInsert<Hovered>,
)>,
```
In scenarios like this, there is a lot of repetition of `On`. These are
expected to be very high-traffic APIs especially in UI contexts, so
ergonomics and readability are critical.
By renaming `Trigger` to `On`, we can make these APIs read more cleanly
and get rid of the repetition:
```rust
app.add_observer(|trigger: On<Explode>| {
info!("Entity {} exploded!", trigger.target());
});
```
```rust
trigger: On<(
Add<Pressed>,
Remove<Pressed>,
Add<InteractionDisabled>,
Remove<InteractionDisabled>,
Insert<Hovered>,
)>,
```
Names like `On<Add<Pressed>>` emphasize the actual event listener nature
more than `Trigger<OnAdd<Pressed>>`, and look cleaner. This *also* frees
up the `Trigger` name if we want to use it for the observer event type,
splitting them out from buffered events (bikeshedding this is out of
scope for this PR though).
For prior art:
[`bevy_eventlistener`](https://github.com/aevyrie/bevy_eventlistener)
used
[`On`](https://docs.rs/bevy_eventlistener/latest/bevy_eventlistener/event_listener/struct.On.html)
for its event listener type. Though in our case, the observer is the
event listener, and `On` is just a type containing information about the
triggered event.
## Solution
Steal from `bevy_event_listener` by @aevyrie and use `On`.
- Rename `Trigger` to `On`
- Rename `OnAdd` to `Add`
- Rename `OnInsert` to `Insert`
- Rename `OnReplace` to `Replace`
- Rename `OnRemove` to `Remove`
- Rename `OnDespawn` to `Despawn`
## Discussion
### Naming Conflicts??
Using a name like `Add` might initially feel like a very bad idea, since
it risks conflict with `core::ops::Add`. However, I don't expect this to
be a big problem in practice.
- You rarely need to actually implement the `Add` trait, especially in
modules that would use the Bevy ECS.
- In the rare cases where you *do* get a conflict, it is very easy to
fix by just disambiguating, for example using `ops::Add`.
- The `Add` event is a struct while the `Add` trait is a trait (duh), so
the compiler error should be very obvious.
For the record, renaming `OnAdd` to `Add`, I got exactly *zero* errors
or conflicts within Bevy itself. But this is of course not entirely
representative of actual projects *using* Bevy.
You might then wonder, why not use `Added`? This would conflict with the
`Added` query filter, so it wouldn't work. Additionally, the current
naming convention for observer events does not use past tense.
### Documentation
This does make documentation slightly more awkward when referring to
`On` or its methods. Previous docs often referred to `Trigger::target`
or "sends a `Trigger`" (which is... a bit strange anyway), which would
now be `On::target` and "sends an observer `Event`".
You can see the diff in this PR to see some of the effects. I think it
should be fine though, we may just need to reword more documentation to
read better.
# Objective
- Update the scroll example to use the latest API.
## Solution
- It now uses the 'children![]' API.
## Testing
- I manually verified that the scrolling was working
## Limitations
- Unfortunately, I couldn't find a way to spawn observers targeting the
entity inside the "fn() -> impl Bundle" function.
Link in the "asset settings" example. The struct was moved.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: theotherphil <phil.j.ellison@gmail.com>
# Objective
The documentation for observers is not very good. This poses a problem
to users, but *also* causes serious problems for engine devs, as they
attempt to improve assorted issues surrounding observers.
This PR:
- Fixes#14084.
- Fixes#14726.
- Fixes#16538.
- Closes#18914, by attempting to solve the same issue.
To keep this PR at all reviewable, I've opted to simply note the various
limitations (some may call them bugs!) in place, rather than attempting
to fix them. There is a huge amount of cleanup work to be done here: see
https://github.com/orgs/bevyengine/projects/17.
## Solution
- Write good module docs for observers, offering bread crumbs to the
most common methods and techniques and comparing-and-contrasting as
needed.
- Fix any actively misleading documentation.
- Try to explain how the various bits of the (public?!) internals are
related.
---------
Co-authored-by: Chris Biscardi <chris@christopherbiscardi.com>
Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
# Objective
#19366 implemented core button widgets, which included the `Depressed`
state component.
`Depressed` was chosen instead of `Pressed` to avoid conflict with the
`Pointer<Pressed>` event, but it is problematic and awkward in many
ways:
- Using the word "depressed" for such a high-traffic type is not great
due to the obvious connection to "depressed" as in depression.
- "Depressed" is not what I would search for if I was looking for a
component like this, and I'm not aware of any other engine or UI
framework using the term.
- `Depressed` is not a very natural pair to the `Pointer<Pressed>`
event.
- It might be because I'm not a native English speaker, but I have very
rarely heard someone say "a button is depressed". Seeing it, my mind
initially goes from "depression??" to "oh, de-pressed, meaning released"
and definitely not "is pressed", even though that *is* also a valid
meaning for it.
A related problem is that the current `Pointer<Pressed>` and
`Pointer<Released>` event names use a different verb tense than all of
our other observer events such as `Pointer<Click>` or
`Pointer<DragStart>`. By fixing this and renaming `Pressed` (and
`Released`), we can then use `Pressed` instead of `Depressed` for the
state component.
Additionally, the `IsHovered` and `IsDirectlyHovered` components added
in #19366 use an inconsistent naming; the other similar components don't
use an `Is` prefix. It also makes query filters like `Has<IsHovered>`
and `With<IsHovered>` a bit more awkward.
This is partially related to Cart's [picking concept
proposal](https://gist.github.com/cart/756e48a149db2838028be600defbd24a?permalink_comment_id=5598154).
## Solution
- Rename `Pointer<Pressed>` to `Pointer<Press>`
- Rename `Pointer<Released>` to `Pointer<Release>`
- Rename `Depressed` to `Pressed`
- Rename `IsHovered` to `Hovered`
- Rename `IsDirectlyHovered` to `DirectlyHovered`
# Objective
Part of #19236
## Solution
Adds a new `bevy_core_widgets` crate containing headless widget
implementations. This PR adds a single `CoreButton` widget, more widgets
to be added later once this is approved.
## Testing
There's an example, ui/core_widgets.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- Fixes#17183
## Solution
- Copied the stress settings from the `many_animated_sprite` example
that were mentioned in the ticket
## Testing
- Run the example
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
As discussed in #19285, some of our names conflict. `Entry` in bevy_ecs
is one of those overly general names.
## Solution
Rename this type (and the related types) to `ComponentEntry`.
---------
Co-authored-by: urben1680 <55257931+urben1680@users.noreply.github.com>
# Objective
I set out with one simple goal: clearly document the differences between
each of the component lifecycle events via module docs.
Unfortunately, no such module existed: the various lifecycle code was
scattered to the wind.
Without a unified module, it's very hard to discover the related types,
and there's nowhere good to put my shiny new documentation.
## Solution
1. Unify the assorted types into a single
`bevy_ecs::component_lifecycle` module.
2. Write docs.
3. Write a migration guide.
## Testing
Thanks CI!
## Follow-up
1. The lifecycle event names are pretty confusing, especially
`OnReplace`. We should consider renaming those. No bikeshedding in my PR
though!
2. Observers need real module docs too :(
3. Any additional functional changes should be done elsewhere; this is a
simple docs and re-org PR.
---------
Co-authored-by: theotherphil <phil.j.ellison@gmail.com>
## Objective
Fixes#19051.
---
## Solution
Originally implemented `compiler_error!()` within bevy_tasks/src/lib.rs
file to provide descriptive message regarding missing feature. However,
a cleaner approach was to add `async_executor` to the array of features
enabled by `multi_threaded` instead. This removes the need for users to
manually add `features = ["multi_threaded", "async_executor"]`
separately as needed to be done previously.
---
## Testing
These changes were tested using a minimal, external project designed to
specifically test whether the standalone `multi_threaded` feature for
`bevy_tasks` with `default-features` disabled worked as intended without
running into any compile-time error.
### How it was tested:
1. A `bevy_tasks_test` binary project was set up in an external
directory.
2. Its `Cargo.toml` was configured to depend on the local `bevy_tasks`,
explicitly disabling default features and enabling only
`multi_threaded`.
3. A simple `bevy_tasks_test/bin/bevy_crates_test.rs` was created and
configured within `Cargo.toml` file where bevy_tasks was set to the
local version of the crate with the modified changes and `cargo add
bevy_platform` was executed through the terminal since that dependency
is also needed to execute the sample examples.
4. Then both the `examples/busy_behavior.rs` and
`examples/idle_behavior.rs` code was added and tested with just the
`multi_threaded` feature was enabled and the code executed successfully.
### Results:
The code executed successfully for both examples where a threadPool was
utilized with 4 tasks and spawning 40 tasks that spin for 100ms.
Demonstrating how the threads finished executing all the tasks
simultaneously after a brief delay of less than a second (this is
referencing `bevy_tasks/examples/busy_behavior.rs`). Alongside the
second example where one thread per logical core was was utilized for a
single spinning task and aside from utilizing the single thread, system
was intended to remain idle as part of good practice when it comes to
handling small workloads. (this is referencing
`bevy_tasks/examples/idle_behavior.rs`).
### How to test:
Reviewers can easily verify this by:
1. Checking out this PR.
2. Creating `cargo new bevy_tasks_test` and the `Cargo.toml` should look
something like this:
```toml
# bevy/tests/compile_fail_tasks/Cargo.toml
[package]
name = "bevy_tasks_test"
version = "0.1.0"
edition = "2021"
publish = false
[dependencies]
# path to bevy_tasks sub-crate to test locally
bevy_tasks = { path = "../../bevy_tasks", default-features = false,
features = ["multi_threaded"] }
bevy_platform = "0.16.1"
```
3. Copying the examples within bevy_creates/examples one by one and
testing them separately within `src/main.rs` to check whether the
examples work.
4. Then simply running `cargo run` within the terminal should suffice to
test if the single `multi_threaded` feature works without the need for
separately adding `async_executor` as `multi_threaded` already uses
`async_executor` internally.
### Platforms tested:
macOS (aarch64). As a `#[cfg]` based compile-time check, behavior should
be consistent across platforms.
# Objective
Fixes#19403
As described in the issue, the objective is to support the use of
systems returning `Result<(), BevyError>` and
`Result<bool, BevyError>` as run conditions. In these cases, the run
condition would hold on `Ok(())` and `Ok(true)` respectively.
## Solution
`IntoSystem<In, bool, M>` cannot be implemented for systems returning
`Result<(), BevyError>` and `Result<bool, BevyError>` as that would
conflict with their trivial implementation of the trait. That led me to
add a method to the sealed trait `SystemCondition` that does the
conversion. In the original case of a system returning `bool`, the
system is returned as is. With the new types, the system is combined
with `map()` to obtain a `bool`.
By the way, I'm confused as to why `SystemCondition` has a generic `In`
parameter as it is only ever used with `In = ()` as far as I can tell.
## Testing
I added a simple test for both type of system. That's minimal but it
felt enough. I could not picture the more complicated tests passing for
a run condition returning `bool` and failing for the new types.
## Doc
I documenting the change on the page of the trait. I had trouble wording
it right but I'm not sure how to improve it. The phrasing "the condition
returns `true`" which reads naturally is now technically incorrect as
the new types return a `Result`. However, the underlying condition
system that the implementing system turns into does indeed return
`bool`. But talking about the implementation details felt too much.
Another possibility is to use another turn of phrase like "the condition
holds" or "the condition checks out". I've left "the condition returns
`true`" in the documentation of `run_if` and the provided methods for
now.
I'm perplexed about the examples. In the first one, why not implement
the condition directly instead of having a system returning it? Is it
from a time of Bevy where you had to implement your conditions that way?
In that case maybe that should be updated. And in the second example I'm
missing the point entirely. As I stated above, I've only seen conditions
used in contexts where they have no input parameter. Here we create a
condition with an input parameter (cannot be used by `run_if`) and we
are using it with `pipe()` which actually doesn't need our system to
implement `SystemCondition`. Both examples are also calling
`IntoSystem::into_system` which should not be encouraged. What am I
missing?
Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.32.0 to
1.33.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/crate-ci/typos/releases">crate-ci/typos's
releases</a>.</em></p>
<blockquote>
<h2>v1.33.1</h2>
<h2>[1.33.1] - 2025-06-02</h2>
<h3>Fixes</h3>
<ul>
<li><em>(dict)</em> Don't correct <code>wasn't</code> to
<code>wasm't</code></li>
</ul>
<h2>v1.33.0</h2>
<h2>[1.33.0] - 2025-06-02</h2>
<h3>Features</h3>
<ul>
<li>Updated the dictionary with the <a
href="https://redirect.github.com/crate-ci/typos/issues/1290">May
2025</a> changes</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/crate-ci/typos/blob/master/CHANGELOG.md">crate-ci/typos's
changelog</a>.</em></p>
<blockquote>
<h2>[1.33.1] - 2025-06-02</h2>
<h3>Fixes</h3>
<ul>
<li><em>(dict)</em> Don't correct <code>wasn't</code> to
<code>wasm't</code></li>
</ul>
<h2>[1.33.0] - 2025-06-02</h2>
<h3>Features</h3>
<ul>
<li>Updated the dictionary with the <a
href="https://redirect.github.com/crate-ci/typos/issues/1290">May
2025</a> changes</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="b1ae8d918b"><code>b1ae8d9</code></a>
chore: Release</li>
<li><a
href="6c5d17de8e"><code>6c5d17d</code></a>
docs: Update changelog</li>
<li><a
href="0a237ba81a"><code>0a237ba</code></a>
Merge pull request <a
href="https://redirect.github.com/crate-ci/typos/issues/1311">#1311</a>
from epage/wasn</li>
<li><a
href="79920cf069"><code>79920cf</code></a>
fix(dict): Don't correct <code>wasn't</code></li>
<li><a
href="e99b2b47d9"><code>e99b2b4</code></a>
chore: Release</li>
<li><a
href="2afc152754"><code>2afc152</code></a>
chore: Release</li>
<li><a
href="544a19b4ae"><code>544a19b</code></a>
docs: Update changelog</li>
<li><a
href="2e0ca28a95"><code>2e0ca28</code></a>
Merge pull request <a
href="https://redirect.github.com/crate-ci/typos/issues/1310">#1310</a>
from epage/may</li>
<li><a
href="94eb4e7b40"><code>94eb4e7</code></a>
feat(dict): May 2025 updates</li>
<li><a
href="a4cce4ca70"><code>a4cce4c</code></a>
Merge pull request <a
href="https://redirect.github.com/crate-ci/typos/issues/1308">#1308</a>
from crate-ci/renovate/schemars-0.x</li>
<li>Additional commits viewable in <a
href="https://github.com/crate-ci/typos/compare/v1.32.0...v1.33.1">compare
view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: François Mockers <mockersf@gmail.com>
# Objective
- Cleanup related to #19495.
## Solution
- Delete `System::component_access()`. It is redundant with
`System::component_access_set().combined_access()`.
## Testing
- None. There are no callers of this function.
# Objective
In the past I had custom data structures containing `Tick`s. I learned
that these need to be regularly checked to clamp them. But there was no
way to hook into that logic so I abandoned storing ticks since then.
Another motivation to open this up some more is to be more able to do a
correct implementation of `System::check_ticks`.
## Solution
Add `CheckChangeTicks` and trigger it in `World::check_change_ticks`.
Make `Tick::check_tick` public.
This event makes it possible to store ticks in components or resources
and have them checked.
I also made `Schedules::check_change_ticks` public so users can store
schedules in custom resources/components for whatever reasons.
## Testing
The logic boils down to a single `World::trigger` call and I don't think
this needs more tests.
## Alternatives
Making this obsolete like with #15683.
---
## Showcase
From the added docs:
```rs
use bevy_ecs::prelude::*;
use bevy_ecs::component::CheckChangeTicks;
#[derive(Resource)]
struct CustomSchedule(Schedule);
let mut world = World::new();
world.add_observer(|tick: Trigger<CheckChangeTicks>, mut schedule: ResMut<CustomSchedule>| {
schedule.0.check_change_ticks(tick.get());
});
```
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Fixes#19136
## Solution
- Add a new container attribute which when set does not emit
`BundleFromComponents`
## Testing
- Did you test these changes?
Yes, a new test was added.
- Are there any parts that need more testing?
Since `BundleFromComponents` is unsafe I made extra sure that I did not
misunderstand its purpose. As far as I can tell, _not_ implementing it
is ok.
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
Nope
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
I don't think the platform is relevant
---
One thing I am not sure about is how to document this? I'll gladly add
it
---------
Signed-off-by: Marcel Müller <neikos@neikos.email>
# Objective
`SystemSet`s are surprisingly rich and nuanced, but are extremely poorly
documented.
Fixes#19536.
## Solution
Explain the basic concept of system sets, how to create them, and give
some opinionated advice about their more advanced functionality.
## Follow-up
I'd like proper module level docs on system ordering that I can link to
here, but they don't exist. Punting to follow-up!
---------
Co-authored-by: theotherphil <phil.j.ellison@gmail.com>
# Objective
Rename `JustifyText`:
* The name `JustifyText` is just ugly.
* It's inconsistent since no other `bevy_text` types have a `Text-`
suffix, only prefix.
* It's inconsistent with the other text layout enum `Linebreak` which
doesn't have a prefix or suffix.
Fixes#19521.
## Solution
Rename `JustifyText` to `Justify`.
Without other context, it's natural to assume the name `Justify` refers
to text justification.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>