# Objective
When running the `gradient` example, part of the content doesn't fit
within the initial window:

The UI requires 1830×930 pixels, but the initial window size is
1280×720.
## Solution
Make ui elements smaller:

Alternative: Use a larger initial window size. I decided against this
because that would make the examples less uniform, make the code less
focused on gradients and not help on web.
# Objective
Certain classes of games, usually those with enormous worlds, require
some amount of support for double-precision. Libraries like `big_space`
exist to allow for large worlds while integrating cleanly with Bevy's
primarily single-precision ecosystem, but even then, games will often
still work directly in double-precision throughout the part of the
pipeline that feeds into the Bevy interface.
Currently, working with double-precision types in Bevy is a pain. `glam`
provides types like `DVec3`, but Bevy doesn't provide double-precision
analogs for `glam` wrappers like `Dir3`. This is mostly because doing so
involves one of:
- code duplication
- generics
- templates (like `glam` uses)
- macros
Each of these has issues that are enough to be deal-breakers as far as
maintainability, usability or readability. To work around this, I'm
putting together `bevy_dmath`, a crate that duplicates `bevy_math` types
and functionality to allow downstream users to enjoy the ergonomics and
power of `bevy_math` in double-precision. For the most part, it's a
smooth process, but in order to fully integrate, there are some
necessary changes that can only be made in `bevy_math`.
## Solution
This PR addresses the first and easiest issue with downstream
double-precision math support: `VectorSpace` currently can only
represent vector spaces over `f32`. This automatically closes the door
to double-precision curves, among other things. This restriction can be
easily lifted by allowing vector spaces to specify the underlying scalar
field. This PR adds a new trait `ScalarField` that satisfies the
properties of a scalar field (the ones that can be upheld statically)
and adds a new associated type `type Scalar: ScalarField` to
`VectorSpace`. It's mostly an unintrusive change. The biggest annoyances
are:
- it touches a lot of curve code
- `bevy_math::ops` doesn't support `f64`, so there are some annoying
workarounds
As far as curves code, I wanted to make this change unintrusive and
bite-sized, so I'm trying to touch as little code as possible. To prove
to myself it can be done, I went ahead and (*not* in this PR) migrated
most of the curves API to support different `ScalarField`s and it went
really smoothly! The ugliest thing was adding `P::Scalar: From<usize>`
in several places. There's an argument to be made here that we should be
using `num-traits`, but that's not immediately relevant. The point is
that for now, the smallest change I could make was to go into every
curve impl and make them generic over `VectorSpace<Scalar = f32>`.
Curves work exactly like before and don't change the user API at all.
# Follow-up
- **Extend `bevy_math::ops` to work with `f64`.** `bevy_math::ops` is
used all over, and if curves are ever going to support different
`ScalarField` types, we'll need to be able to use the correct `std` or
`libm` ops for `f64` types as well. Adding an `ops64` mod turned out to
be really ugly, but I'll point out the maintenance burden is low because
we're not going to be adding new floating-point ops anytime soon.
Another solution is to build a floating-point trait that calls the right
op variant and impl it for `f32` and `f64`. This reduces maintenance
burden because on the off chance we ever *do* want to go modify it, it's
all tied together: you can't change the interface on one without
changing the trait, which forces you to update the other. A third option
is to use `num-traits`, which is basically option 2 but someone else did
the work for us. They already support `no_std` using `libm`, so it would
be more or less a drop-in replacement. They're missing a couple
floating-point ops like `floor` and `ceil`, but we could make our own
floating-point traits for those (there's even the potential for
upstreaming them into `num-traits`).
- **Tweak curves to accept vector spaces over any `ScalarField`.**
Curves are ready to support custom scalar types as soon as the bullet
above is addressed. I will admit that the code is not as fun to look at:
`P::Scalar` instead of `f32` everywhere. We could consider an alternate
design where we use `f32` even to interpolate something like a `DVec3`,
but personally I think that's a worse solution than parameterizing
curves over the vector space's scalar type. At the end of the day, it's
not really bad to deal with in my opinion... `ScalarType` supports
enough operations that working with them is almost like working with raw
float types, and it unlocks a whole ecosystem for games that want to use
double-precision.
fix: [Ensure linear volume subtraction does not go below zero
](https://github.com/bevyengine/bevy/issues/19417)
## Solution
- Clamp the result of linear volume subtraction to a minimum of 0.0
- Add a new test case to verify behavior when subtracting beyond zero
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
# Objective
- Enable hot patching systems with subsecond
- Fixes#19296
## Solution
- First commit is the naive thin layer
- Second commit only check the jump table when the code is hot patched
instead of on every system execution
- Depends on https://github.com/DioxusLabs/dioxus/pull/4153 for a nicer
API, but could be done without
- Everything in second commit is feature gated, it has no impact when
the feature is not enabled
## Testing
- Check dependencies without the feature enabled: nothing dioxus in tree
- Run the new example: text and color can be changed
---------
Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
Co-authored-by: JMS55 <47158642+JMS55@users.noreply.github.com>
The first 4 commits are designed to be reviewed independently.
- Mark TAA non-experimental now that motion vectors are written for
skinned and morphed meshes, along with skyboxes, and add it to
DefaultPlugins
- Adjust halton sequence to match what DLSS is going to use, doesn't
really affect anything, but may as well
- Make MipBias a required component on TAA instead of inserting it in
the render world
- Remove MipBias, TemporalJitter, RenderLayers, etc from the render
world if they're removed from the main world (fixes a retained render
world bug)
- Remove TAA components from the render world properly if
TemporalAntiAliasing is removed from the main world (fixes a retained
render world bug)
- extract_taa_settings() now has to query over `Option<&mut
TemporalAntiAliasing>`, which will match every single camera, in order
to cover cameras that had TemporalAntiAliasing removed this frame. This
kind of sucks, but I can't think of anything better.
- We probably have the same bug with every other rendering feature
component we have.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- Due to recent changes related to #19024, the
`compute_shader_game_of_life` example panics on some machines especially
on Linux.
- This is due to us switching more shaders to embedded shaders - this
means the compute shader in this example takes more than one frame to
load.
- The panic in the example occurs if the shader fails to load by the
first frame (since the pipeline considers that an error).
## Solution
- Make the example do nothing if the shader isn't loaded yet. This has
the effect of waiting for the shader to load.
## Testing
- Tested the example on my Linux laptop.
# Objective
Minimal effort to address feedback here:
https://github.com/bevyengine/bevy/pull/19345#discussion_r2107844018
more thoroughly.
## Solution
- Remove hardcoded label string comparisons and make more use of the new
enum added during review
- Resist temptation to let this snowball this into a huge refactor
- Maybe come back later for a few other small improvements
## Testing
`cargo run --example box_shadow`
# Objective
Renames `Timer::finished` and `Timer::paused` to `Timer::is_finished`
and `Timer::is_paused` to align the public APIs for `Time`, `Timer`, and
`Stopwatch`.
Fixes#19110
# Objective
Fixes#19385
Note: this has shader errors due to #19383 and should probably be merged
after #19384
## Solution
- Move the example to the UI testbed
- Adjust label contents and cell size so that every test case fits on
the screen
- Minor tidying, slightly less harsh colors while preserving the
intentional debug coloring
## Testing
`cargo run --example testbed_ui`

---------
Co-authored-by: François Mockers <mockersf@gmail.com>
# Objective
- Addresses the previous example's lack of visual appeal and clarity. It
was missing labels for clear distinction of the shadow settings used on
each of the shapes. The suggestion in the linked issue was to either
just visually update and add labels or to collapse example to a single
node with adjustable settings.
- Fixes#19240
## Solution
- Replace the previous static example with a single, central node with
adjustable settings as per issue suggestion.
- Implement button-based setting adjustments. Unfortunately slider
widgets don't seem available yet and I didn't want to further bloat the
example.
- Improve overall aesthetics of the example -- although color pallette
could still be improved. flat gray tones are probably not the best
choice as a contrast to the shadow, but the white border does help in
that aspect.
- Dynamically recolor shadows for visual clarity when increasing shadow
count.
- Add Adjustable Settings:
- Shape selection
- Shadow X/Y offset, blur, spread, and count
- Add Reset button to restore default settings
The disadvantage of this solution is that the old example code would
have probably been easier to digest as the new example is quite bloated
in comparison. Alternatively I could also just implement labels and fix
aesthetics of the old example without adding functionality for
adjustable settings, _but_ I personally feel like interactive examples
are more engaging to users.
## Testing
- Did you test these changes? If so, how? `cargo run --example
box_shadow` and functionality of all features of the example.
- Are there any parts that need more testing? Not that I am aware of.
- How can other people (reviewers) test your changes? Is there anything
specific they need to know? Not really, it should be pretty
straightforward just running the new example and testing the feats.
---
## Showcase


---------
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
# Objective
Remove `ArchetypeComponentId` and `archetype_component_access`.
Following #16885, they are no longer used by the engine, so we can stop
spending time calculating them or space storing them.
## Solution
Remove `ArchetypeComponentId` and everything that touches it.
The `System::update_archetype_component_access` method no longer needs
to update `archetype_component_access`. We do still need to update query
caches, but we no longer need to do so *before* running the system. We'd
have to touch every caller anyway if we gave the method a better name,
so just remove `System::update_archetype_component_access` and
`SystemParam::new_archetype` entirely, and update the query cache in
`Query::get_param`.
The `Single` and `Populated` params also need their query caches updated
in `SystemParam::validate_param`, so change `validate_param` to take
`&mut Self::State` instead of `&Self::State`.
# Objective
- Enable state scoped entities by default
- Provide a way to disable it when needed
---------
Co-authored-by: Ben Frankel <ben.frankel7@gmail.com>
# Objective
Improve the `tab_navigation` example.
## Solution
* Set different `TabIndex`s for the buttons of each group.
* Label each button with its associated `TabIndex`.
* Reduce the code duplication using a loop.
I tried to flatten it further using the new spawning APIs and
`children!` macro but not sure what the current best way to attach the
observers is.
# Objective
Fix some grammatical errors: it's -> its
Not the most useful commit in the world, but I saw a couple of these and
decided to fix the lot.
## Solution
-
## Testing
-
# Objective
We want to extend our examples with a new category "usage" to
demonstrate common use cases (see bevyengine/bevy-website#2131). This PR
adds an example of animated cooldowns on button clicks.
## Solution
- New example in "usage" directory
- Implement a cooldown with an animated child Node
## Testing
- I ran this on Linux
- [x] test web (with bevy CLI: `bevy run --example cooldown web --open`)
---------
Co-authored-by: Thierry Berger <contact@thierryberger.com>
Co-authored-by: Ida "Iyes" <40234599+inodentry@users.noreply.github.com>
# Objective
- Simplify `Camera` initialization
- allow effects to require HDR
## Solution
- Split out `Camera.hdr` into a marker `Hdr` component
## Testing
- ran `bloom_3d` example
---
## Showcase
```rs
// before
commands.spawn((
Camera3d
Camera {
hdr: true
..Default::default()
}
))
// after
commands.spawn((Camera3d, Hdr));
// other rendering components can require that the camera enables hdr!
// currently implemented for Bloom, AutoExposure, and Atmosphere.
#[require(Hdr)]
pub struct Bloom;
```
[Explanation](https://bevyengine.org/learn/contribute/helping-out/explaining-examples/)
for the 2d shapes example, taken from the original HackMD document and
edited a bit.
This example is a strange one, it's eye-catching mostly because it's the
first example (at time of writing) in the examples page. That being
said, the example does a decent amount of teaching utility to it: we can
explain the bevy math-shape to mesh pipeline, which illuminates a way of
transforming one form of data (abstract, mathematical shape
descriptions) into another (meshes) which may be novel or inspirational
to some users.
---------
Co-authored-by: theotherphil <phil.j.ellison@gmail.com>
# Objective
When user presses <kbd>3</kbd>, the falloff mode should be changed to
`ExponentialSquared` as described in the instructions, but it's not in
fact.
Online Example: https://bevyengine.org/examples-webgpu/3d-rendering/fog/
## Solution
Change it to `ExponentialSquared`
## Testing
- Did you test these changes? If so, how?
Yes, by `cargo run --example fog`
- Are there any parts that need more testing?
No.
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
```
cargo run --example fog
```
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
N/A
# Objective
- Allow users to get the playback position of playing audio.
## Solution
- Add a `position` method to `AudioSinkPlayback`
- Implement it for `AudioSink` and `SpatialAudioSink`
## Testing
- Updated `audio_control` example to show playback position
# Objective
The new viewport example allocates a texture in main memory, even though
it's only needed on the GPU. Also fix an unnecessary warning when a
viewport's texture doesn't exist CPU-side.
## Testing
Run the `viewport_node` example.
# Objective
allow specifying the left/top/right/bottom border colors separately for
ui elements
fixes#14773
## Solution
- change `BorderColor` to
```rs
pub struct BorderColor {
pub left: Color,
pub top: Color,
pub right: Color,
pub bottom: Color,
}
```
- generate one ui node per distinct border color, set flags for the
active borders
- render only the active borders
i chose to do this rather than adding multiple colors to the
ExtractedUiNode in order to minimize the impact for the common case
where all border colors are the same.
## Testing
modified the `borders` example to use separate colors:

the behaviour is a bit weird but it mirrors html/css border behaviour.
---
## Migration:
To keep the existing behaviour, just change `BorderColor(color)` into
`BorderColor::all(color)`.
---------
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
# Objective
Accessibility features don't work with the UI `button` example because
`InputFocus` must be set for the accessibility systems to recognise the
button.
Fixes#18760
## Solution
* Set the button entity as the `InputFocus` when it is hovered or
pressed.
* Call `set_changed` on the `Button` component when the button's state
changes to hovered or pressed (the accessibility system's only update
the button's state when the `Button` component is marked as changed).
## Testing
Install NVDA, it should say "hover" when the button is hovered and
"pressed" when the button is pressed.
The bounds of the accessibility node are reported incorrectly. I thought
we fixed this, I'll take another look at it. It's not a problem with
this PR.
Stores mesh names from glTF files in GltfMeshName component rather than
Name component, making both GltfMeshName and GltfMaterialName behave
like strings via Deref.
# Objective
Fixed the side effects of #19287
Fixes Examples that modify gltf materials are broken #19322
## Solution
Add GltfMeshName component and Deref implementations
Stores mesh names from glTF files in GltfMeshName component rather than
Name component, making both GltfMeshName and GltfMaterialName behave
like strings via Deref.
## Testing
cargo run --example depth_of_field
cargo run --example lightmaps
cargo run --example mixed_lighting
They are consistent with the situation before the error occurred.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Rob Parrett <robparrett@gmail.com>
# Objective
Closes#19175
Make `LogDiagnosticsState` public to be able to edit its filters
## Solution
Make `LogDiagnosticsState` public and add methods to allow editing the
duration and filter
## Testing
`cargo run -p ci`
## Showcase
Updated `log_diagnostics` example

## Objective
Fix the misleading 2d anchor API where `Anchor` is a component and
required by `Text2d` but is stored on a field for sprites.
Fixes#18367
## Solution
Remove the `anchor` field from `Sprite` and require `Anchor` instead.
## Migration Guide
The `anchor` field has been removed from `Sprite`. Instead the `Anchor`
component is now a required component on `Sprite`.
# Objective
Allowing drawing of UI nodes with a gradient instead of a flat color.
## Solution
The are three gradient structs corresponding to the three types of
gradients supported: `LinearGradient`, `ConicGradient` and
`RadialGradient`. These are then wrapped in a `Gradient` enum
discriminator which has `Linear`, `Conic` and `Radial` variants.
Each gradient type consists of the geometric properties for that
gradient and a list of color stops.
Color stops consist of a color, a position or angle and an optional
hint. If no position is specified for a stop, it's evenly spaced between
the previous and following stops. Color stop positions are absolute, if
you specify a list of stops:
```vec


Conic gradients can be used to draw simple pie charts like in CSS:

# Objective
[see original
comment](https://github.com/bevyengine/bevy/pull/18801#issuecomment-2796981745)
> Alternately, could we store it on the World instead of a global? I
think we have a World nearby whenever we call default_error_handler().
That would avoid the need for atomics or locks, since we could do
ordinary reads and writes to the World.
Global error handlers don't actually need to be global – per world is
enough. This allows using different handlers for different worlds and
also removes the restrictions on changing the handler only once.
## Solution
Each `World` can now store its own error handler in a resource.
For convenience, you can also set the default error handler for an
`App`, which applies it to the worlds of all `SubApp`s. The old behavior
of only being able to set the error handler once is kept for apps.
We also don't need the `configurable_error_handler` feature anymore now.
## Testing
New/adjusted tests for failing schedule systems & observers.
---
## Showcase
```rust
App::new()
.set_error_handler(info)
…
```
# Objective
There are two problems this aims to solve.
First, `Entity::index` is currently a `u32`. That means there are
`u32::MAX + 1` possible entities. Not only is that awkward, but it also
make `Entity` allocation more difficult. I discovered this while working
on remote entity reservation, but even on main, `Entities` doesn't
handle the `u32::MAX + 1` entity very well. It can not be batch reserved
because that iterator uses exclusive ranges, which has a maximum upper
bound of `u32::MAX - 1`. In other words, having `u32::MAX` as a valid
index can be thought of as a bug right now. We either need to make that
invalid (this PR), which makes Entity allocation cleaner and makes
remote reservation easier (because the length only needs to be u32
instead of u64, which, in atomics is a big deal), or we need to take
another pass at `Entities` to make it handle the `u32::MAX` index
properly.
Second, `TableRow`, `ArchetypeRow` and `EntityIndex` (a type alias for
u32) all have `u32` as the underlying type. That means using these as
the index type in a `SparseSet` uses 64 bits for the sparse list because
it stores `Option<IndexType>`. By using `NonMaxU32` here, we cut the
memory of that list in half. To my knowledge, `EntityIndex` is the only
thing that would really benefit from this niche. `TableRow` and
`ArchetypeRow` I think are not stored in an `Option` in bulk. But if
they ever are, this would help. Additionally this ensures
`TableRow::INVALID` and `ArchetypeRow::INVALID` never conflict with an
actual row, which in a nice bonus.
As a related note, if we do components as entities where `ComponentId`
becomes `Entity`, the the `SparseSet<ComponentId>` will see a similar
memory improvement too.
## Solution
Create a new type `EntityRow` that wraps `NonMaxU32`, similar to
`TableRow` and `ArchetypeRow`.
Change `Entity::index` to this type.
## Downsides
`NonMax` is implemented as a `NonZero` with a binary inversion. That
means accessing and storing the value takes one more instruction. I
don't think that's a big deal, but it's worth mentioning.
As a consequence, `to_bits` uses `transmute` to skip the inversion which
keeps it a nop. But that also means that ordering has now flipped. In
other words, higher indices are considered less than lower indices. I
don't think that's a problem, but it's also worth mentioning.
## Alternatives
We could keep the index as a u32 type and just document that `u32::MAX`
is invalid, modifying `Entities` to ensure it never gets handed out.
(But that's not enforced by the type system.) We could still take
advantage of the niche here in `ComponentSparseSet`. We'd just need some
unsafe manual conversions, which is probably fine, but opens up the
possibility for correctness problems later.
We could change `Entities` to fully support the `u32::MAX` index. (But
that makes `Entities` more complex and potentially slightly slower.)
## Testing
- CI
- A few tests were changed because they depend on different ordering and
`to_bits` values.
## Future Work
- It might be worth removing the niche on `Entity::generation` since
there is now a different niche.
- We could move `Entity::generation` into it's own type too for clarity.
- We should change `ComponentSparseSet` to take advantage of the new
niche. (This PR doesn't change that yet.)
- Consider removing or updating `Identifier`. This is only used for
`Entity`, so it might be worth combining since `Entity` is now more
unique.
---------
Co-authored-by: atlv <email@atlasdostal.com>
Co-authored-by: Zachary Harrold <zac@harrold.com.au>
# Objective
Provide a generic `impl SystemParam for Option<P>` that uses system
parameter validation. This immediately gives useful impls for params
like `EventReader` and `GizmosState` that are defined in terms of `Res`.
It also allows third-party system parameters to be usable with `Option`,
which was previously impossible due to orphan rules.
Note that this is a behavior change for `Option<Single>`. It currently
fails validation if there are multiple matching entities, but with this
change it will pass validation and produce `None`.
Also provide an impl for `Result<P, SystemParamValidationError>`. This
allows systems to inspect the error if necessary, either for bubbling it
up or for checking the `skipped` flag.
Fixes#12634Fixes#14949
Related to #18516
## Solution
Add generic `SystemParam` impls for `Option` and `Result`, and remove
the impls for specific types.
Update documentation and `fallible_params` example with the new
semantics for `Option<Single>`.
# Objective
Fixes a part of #14274.
Bevy has an incredibly inconsistent naming convention for its system
sets, both internally and across the ecosystem.
<img alt="System sets in Bevy"
src="https://github.com/user-attachments/assets/d16e2027-793f-4ba4-9cc9-e780b14a5a1b"
width="450" />
*Names of public system set types in Bevy*
Most Bevy types use a naming of `FooSystem` or just `Foo`, but there are
also a few `FooSystems` and `FooSet` types. In ecosystem crates on the
other hand, `FooSet` is perhaps the most commonly used name in general.
Conventions being so wildly inconsistent can make it harder for users to
pick names for their own types, to search for system sets on docs.rs, or
to even discern which types *are* system sets.
To reign in the inconsistency a bit and help unify the ecosystem, it
would be good to establish a common recommended naming convention for
system sets in Bevy itself, similar to how plugins are commonly suffixed
with `Plugin` (ex: `TimePlugin`). By adopting a consistent naming
convention in first-party Bevy, we can softly nudge ecosystem crates to
follow suit (for types where it makes sense to do so).
Choosing a naming convention is also relevant now, as the [`bevy_cli`
recently adopted
lints](https://github.com/TheBevyFlock/bevy_cli/pull/345) to enforce
naming for plugins and system sets, and the recommended naming used for
system sets is still a bit open.
## Which Name To Use?
Now the contentious part: what naming convention should we actually
adopt?
This was discussed on the Bevy Discord at the end of last year, starting
[here](<https://discord.com/channels/691052431525675048/692572690833473578/1310659954683936789>).
`FooSet` and `FooSystems` were the clear favorites, with `FooSet` very
narrowly winning an unofficial poll. However, it seems to me like the
consensus was broadly moving towards `FooSystems` at the end and after
the poll, with Cart
([source](https://discord.com/channels/691052431525675048/692572690833473578/1311140204974706708))
and later Alice
([source](https://discord.com/channels/691052431525675048/692572690833473578/1311092530732859533))
and also me being in favor of it.
Let's do a quick pros and cons list! Of course these are just what I
thought of, so take it with a grain of salt.
`FooSet`:
- Pro: Nice and short!
- Pro: Used by many ecosystem crates.
- Pro: The `Set` suffix comes directly from the trait name `SystemSet`.
- Pro: Pairs nicely with existing APIs like `in_set` and
`configure_sets`.
- Con: `Set` by itself doesn't actually indicate that it's related to
systems *at all*, apart from the implemented trait. A set of what?
- Con: Is `FooSet` a set of `Foo`s or a system set related to `Foo`? Ex:
`ContactSet`, `MeshSet`, `EnemySet`...
`FooSystems`:
- Pro: Very clearly indicates that the type represents a collection of
systems. The actual core concept, system(s), is in the name.
- Pro: Parallels nicely with `FooPlugins` for plugin groups.
- Pro: Low risk of conflicts with other names or misunderstandings about
what the type is.
- Pro: In most cases, reads *very* nicely and clearly. Ex:
`PhysicsSystems` and `AnimationSystems` as opposed to `PhysicsSet` and
`AnimationSet`.
- Pro: Easy to search for on docs.rs.
- Con: Usually results in longer names.
- Con: Not yet as widely used.
Really the big problem with `FooSet` is that it doesn't actually
describe what it is. It describes what *kind of thing* it is (a set of
something), but not *what it is a set of*, unless you know the type or
check its docs or implemented traits. `FooSystems` on the other hand is
much more self-descriptive in this regard, at the cost of being a bit
longer to type.
Ultimately, in some ways it comes down to preference and how you think
of system sets. Personally, I was originally in favor of `FooSet`, but
have been increasingly on the side of `FooSystems`, especially after
seeing what the new names would actually look like in Avian and now
Bevy. I prefer it because it usually reads better, is much more clearly
related to groups of systems than `FooSet`, and overall *feels* more
correct and natural to me in the long term.
For these reasons, and because Alice and Cart also seemed to share a
preference for it when it was previously being discussed, I propose that
we adopt a `FooSystems` naming convention where applicable.
## Solution
Rename Bevy's system set types to use a consistent `FooSet` naming where
applicable.
- `AccessibilitySystem` → `AccessibilitySystems`
- `GizmoRenderSystem` → `GizmoRenderSystems`
- `PickSet` → `PickingSystems`
- `RunFixedMainLoopSystem` → `RunFixedMainLoopSystems`
- `TransformSystem` → `TransformSystems`
- `RemoteSet` → `RemoteSystems`
- `RenderSet` → `RenderSystems`
- `SpriteSystem` → `SpriteSystems`
- `StateTransitionSteps` → `StateTransitionSystems`
- `RenderUiSystem` → `RenderUiSystems`
- `UiSystem` → `UiSystems`
- `Animation` → `AnimationSystems`
- `AssetEvents` → `AssetEventSystems`
- `TrackAssets` → `AssetTrackingSystems`
- `UpdateGizmoMeshes` → `GizmoMeshSystems`
- `InputSystem` → `InputSystems`
- `InputFocusSet` → `InputFocusSystems`
- `ExtractMaterialsSet` → `MaterialExtractionSystems`
- `ExtractMeshesSet` → `MeshExtractionSystems`
- `RumbleSystem` → `RumbleSystems`
- `CameraUpdateSystem` → `CameraUpdateSystems`
- `ExtractAssetsSet` → `AssetExtractionSystems`
- `Update2dText` → `Text2dUpdateSystems`
- `TimeSystem` → `TimeSystems`
- `AudioPlaySet` → `AudioPlaybackSystems`
- `SendEvents` → `EventSenderSystems`
- `EventUpdates` → `EventUpdateSystems`
A lot of the names got slightly longer, but they are also a lot more
consistent, and in my opinion the majority of them read much better. For
a few of the names I took the liberty of rewording things a bit;
definitely open to any further naming improvements.
There are still also cases where the `FooSystems` naming doesn't really
make sense, and those I left alone. This primarily includes system sets
like `Interned<dyn SystemSet>`, `EnterSchedules<S>`, `ExitSchedules<S>`,
or `TransitionSchedules<S>`, where the type has some special purpose and
semantics.
## Todo
- [x] Should I keep all the old names as deprecated type aliases? I can
do this, but to avoid wasting work I'd prefer to first reach consensus
on whether these renames are even desired.
- [x] Migration guide
- [x] Release notes
# Objective
- Alternative to and builds on top of #16284.
- Fixes#15849.
## Solution
- Rename component `StateScoped` to `DespawnOnExitState`.
- Rename system `clear_state_scoped_entities` to
`despawn_entities_on_exit_state`.
- Add `DespawnOnEnterState` and `despawn_entities_on_enter_state` which
is the `OnEnter` equivalent.
> [!NOTE]
> Compared to #16284, the main change is that I did the rename in such a
way as to keep the terms `OnExit` and `OnEnter` together. In my own
game, I was adding `VisibleOnEnterState` and `HiddenOnExitState` and
when naming those, I kept the `OnExit` and `OnEnter` together. When I
checked #16284 it stood out to me that the naming was a bit awkward.
Putting the `State` in the middle and breaking up `OnEnter` and `OnExit`
also breaks searching for those terms.
## Open questions
1. Should we split `enable_state_scoped_entities` into two functions,
one for the `OnEnter` and one for the `OnExit`? I personally have zero
need thus far for the `OnEnter` version, so I'd be interested in not
having this enabled unless I ask for it.
2. If yes to 1., should we follow my lead in my `Visibility` state
components (see below) and name these
`app.enable_despawn_entities_on_enter_state()` and
`app.enable_despawn_entities_on_exit_state()`, which IMO says what it
does on the tin?
## Testing
Ran all changed examples.
## Side note: `VisibleOnEnterState` and `HiddenOnExitState`
For reference to anyone else and to help with the open questions, I'm
including the code I wrote for controlling entity visibility when a
state is entered/exited.
<details>
<summary>visibility.rs</summary>
```rust
use bevy_app::prelude::*;
use bevy_ecs::prelude::*;
use bevy_reflect::prelude::*;
use bevy_render::prelude::*;
use bevy_state::{prelude::*, state::StateTransitionSteps};
use tracing::*;
pub trait AppExtStates {
fn enable_visible_entities_on_enter_state<S: States>(&mut self) -> &mut Self;
fn enable_hidden_entities_on_exit_state<S: States>(&mut self) -> &mut Self;
}
impl AppExtStates for App {
fn enable_visible_entities_on_enter_state<S: States>(&mut self) -> &mut Self {
self.main_mut()
.enable_visible_entities_on_enter_state::<S>();
self
}
fn enable_hidden_entities_on_exit_state<S: States>(&mut self) -> &mut Self {
self.main_mut().enable_hidden_entities_on_exit_state::<S>();
self
}
}
impl AppExtStates for SubApp {
fn enable_visible_entities_on_enter_state<S: States>(&mut self) -> &mut Self {
if !self
.world()
.contains_resource::<Events<StateTransitionEvent<S>>>()
{
let name = core::any::type_name::<S>();
warn!("Visible entities on enter state are enabled for state `{}`, but the state isn't installed in the app!", name);
}
// We work with [`StateTransition`] in set
// [`StateTransitionSteps::ExitSchedules`] as opposed to [`OnExit`],
// because [`OnExit`] only runs for one specific variant of the state.
self.add_systems(
StateTransition,
update_to_visible_on_enter_state::<S>.in_set(StateTransitionSteps::ExitSchedules),
)
}
fn enable_hidden_entities_on_exit_state<S: States>(&mut self) -> &mut Self {
if !self
.world()
.contains_resource::<Events<StateTransitionEvent<S>>>()
{
let name = core::any::type_name::<S>();
warn!("Hidden entities on exit state are enabled for state `{}`, but the state isn't installed in the app!", name);
}
// We work with [`StateTransition`] in set
// [`StateTransitionSteps::ExitSchedules`] as opposed to [`OnExit`],
// because [`OnExit`] only runs for one specific variant of the state.
self.add_systems(
StateTransition,
update_to_hidden_on_exit_state::<S>.in_set(StateTransitionSteps::ExitSchedules),
)
}
}
#[derive(Clone, Component, Debug, Reflect)]
#[reflect(Component, Debug)]
pub struct VisibleOnEnterState<S: States>(pub S);
#[derive(Clone, Component, Debug, Reflect)]
#[reflect(Component, Debug)]
pub struct HiddenOnExitState<S: States>(pub S);
/// Makes entities marked with [`VisibleOnEnterState<S>`] visible when the state
/// `S` is entered.
pub fn update_to_visible_on_enter_state<S: States>(
mut transitions: EventReader<StateTransitionEvent<S>>,
mut query: Query<(&VisibleOnEnterState<S>, &mut Visibility)>,
) {
// We use the latest event, because state machine internals generate at most
// 1 transition event (per type) each frame. No event means no change
// happened and we skip iterating all entities.
let Some(transition) = transitions.read().last() else {
return;
};
if transition.entered == transition.exited {
return;
}
let Some(entered) = &transition.entered else {
return;
};
for (binding, mut visibility) in query.iter_mut() {
if binding.0 == *entered {
visibility.set_if_neq(Visibility::Visible);
}
}
}
/// Makes entities marked with [`HiddenOnExitState<S>`] invisible when the state
/// `S` is exited.
pub fn update_to_hidden_on_exit_state<S: States>(
mut transitions: EventReader<StateTransitionEvent<S>>,
mut query: Query<(&HiddenOnExitState<S>, &mut Visibility)>,
) {
// We use the latest event, because state machine internals generate at most
// 1 transition event (per type) each frame. No event means no change
// happened and we skip iterating all entities.
let Some(transition) = transitions.read().last() else {
return;
};
if transition.entered == transition.exited {
return;
}
let Some(exited) = &transition.exited else {
return;
};
for (binding, mut visibility) in query.iter_mut() {
if binding.0 == *exited {
visibility.set_if_neq(Visibility::Hidden);
}
}
}
```
</details>
---------
Co-authored-by: Benjamin Brienen <Benjamin.Brienen@outlook.com>
Co-authored-by: Ben Frankel <ben.frankel7@gmail.com>
The LogPlugin now allows overriding the default
`tracing_subscriber::fmt::Layer` through a new `fmt_layer` option. This
enables customization of the default log output format without having to
replace the entire logging system.
For example, to disable timestamps in the log output:
```rust
fn fmt_layer(_app: &mut App) -> Option<bevy::log::BoxedFmtLayer> {
Some(Box::new(
bevy::log::tracing_subscriber::fmt::Layer::default()
.without_time()
.with_writer(std::io::stderr),
))
}
fn main() {
App::new()
.add_plugins(DefaultPlugins.set(bevy::log::LogPlugin {
fmt_layer,
..default()
}))
.run();
}
```
This is different from the existing `custom_layer` option, because that
option _adds_ additional layers to the subscriber, but can't modify the
default formatter layer (at least, not to my knowledge).
I almost always disable timestamps in my Bevy logs, and usually also
tweak other default log formatting (such as `with_span_events`), which
made it so that I always had to disable the default logger. This allows
me to use everything the Bevy logger supports (including tracy support),
while still formatting the default logs the way I like them.
---------
Signed-off-by: Jean Mertz <git@jeanmertz.com>
# Objective
Add a viewport widget.
## Solution
- Add a new `ViewportNode` component to turn a UI node into a viewport.
- Add `viewport_picking` to pass pointer inputs from other pointers to
the viewport's pointer.
- Notably, this is somewhat functionally different from the viewport
widget in [the editor
prototype](https://github.com/bevyengine/bevy_editor_prototypes/pull/110/files#L124),
which just moves the pointer's location onto the render target. Viewport
widgets have their own pointers.
- Care is taken to handle dragging in and out of viewports.
- Add `update_viewport_render_target_size` to update the viewport node's
render target's size if the node size changes.
- Feature gate picking-related viewport items behind
`bevy_ui_picking_backend`.
## Testing
I've been using an example I made to test the widget (and added it as
`viewport_node`):
<details><summary>Code</summary>
```rust
//! A simple scene to demonstrate spawning a viewport widget. The example will demonstrate how to
//! pick entities visible in the widget's view.
use bevy::picking::pointer::PointerInteraction;
use bevy::prelude::*;
use bevy::ui::widget::ViewportNode;
use bevy::{
image::{TextureFormatPixelInfo, Volume},
window::PrimaryWindow,
};
use bevy_render::{
camera::RenderTarget,
render_resource::{
Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages,
},
};
fn main() {
App::new()
.add_plugins((DefaultPlugins, MeshPickingPlugin))
.add_systems(Startup, test)
.add_systems(Update, draw_mesh_intersections)
.run();
}
#[derive(Component, Reflect, Debug)]
#[reflect(Component)]
struct Shape;
fn test(
mut commands: Commands,
window: Query<&Window, With<PrimaryWindow>>,
mut images: ResMut<Assets<Image>>,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
// Spawn a UI camera
commands.spawn(Camera3d::default());
// Set up an texture for the 3D camera to render to
let window = window.get_single().unwrap();
let window_size = window.physical_size();
let size = Extent3d {
width: window_size.x,
height: window_size.y,
..default()
};
let format = TextureFormat::Bgra8UnormSrgb;
let image = Image {
data: Some(vec![0; size.volume() * format.pixel_size()]),
texture_descriptor: TextureDescriptor {
label: None,
size,
dimension: TextureDimension::D2,
format,
mip_level_count: 1,
sample_count: 1,
usage: TextureUsages::TEXTURE_BINDING
| TextureUsages::COPY_DST
| TextureUsages::RENDER_ATTACHMENT,
view_formats: &[],
},
..default()
};
let image_handle = images.add(image);
// Spawn the 3D camera
let camera = commands
.spawn((
Camera3d::default(),
Camera {
// Render this camera before our UI camera
order: -1,
target: RenderTarget::Image(image_handle.clone().into()),
..default()
},
))
.id();
// Spawn something for the 3D camera to look at
commands
.spawn((
Mesh3d(meshes.add(Cuboid::new(5.0, 5.0, 5.0))),
MeshMaterial3d(materials.add(Color::WHITE)),
Transform::from_xyz(0.0, 0.0, -10.0),
Shape,
))
// We can observe pointer events on our objects as normal, the
// `bevy::ui::widgets::viewport_picking` system will take care of ensuring our viewport
// clicks pass through
.observe(on_drag_cuboid);
// Spawn our viewport widget
commands
.spawn((
Node {
position_type: PositionType::Absolute,
top: Val::Px(50.0),
left: Val::Px(50.0),
width: Val::Px(200.0),
height: Val::Px(200.0),
border: UiRect::all(Val::Px(5.0)),
..default()
},
BorderColor(Color::WHITE),
ViewportNode::new(camera),
))
.observe(on_drag_viewport);
}
fn on_drag_viewport(drag: Trigger<Pointer<Drag>>, mut node_query: Query<&mut Node>) {
if matches!(drag.button, PointerButton::Secondary) {
let mut node = node_query.get_mut(drag.target()).unwrap();
if let (Val::Px(top), Val::Px(left)) = (node.top, node.left) {
node.left = Val::Px(left + drag.delta.x);
node.top = Val::Px(top + drag.delta.y);
};
}
}
fn on_drag_cuboid(drag: Trigger<Pointer<Drag>>, mut transform_query: Query<&mut Transform>) {
if matches!(drag.button, PointerButton::Primary) {
let mut transform = transform_query.get_mut(drag.target()).unwrap();
transform.rotate_y(drag.delta.x * 0.02);
transform.rotate_x(drag.delta.y * 0.02);
}
}
fn draw_mesh_intersections(
pointers: Query<&PointerInteraction>,
untargetable: Query<Entity, Without<Shape>>,
mut gizmos: Gizmos,
) {
for (point, normal) in pointers
.iter()
.flat_map(|interaction| interaction.iter())
.filter_map(|(entity, hit)| {
if !untargetable.contains(*entity) {
hit.position.zip(hit.normal)
} else {
None
}
})
{
gizmos.arrow(point, point + normal.normalize() * 0.5, Color::WHITE);
}
}
```
</details>
## Showcase
https://github.com/user-attachments/assets/39f44eac-2c2a-4fd9-a606-04171f806dc1
## Open Questions
- <del>Not sure whether the entire widget should be feature gated behind
`bevy_ui_picking_backend` or not? I chose a partial approach since maybe
someone will want to use the widget without any picking being
involved.</del>
- <del>Is `PickSet::Last` the expected set for `viewport_picking`?
Perhaps `PickSet::Input` is more suited.</del>
- <del>Can `dragged_last_frame` be removed in favor of a better dragging
check? Another option that comes to mind is reading `Drag` and `DragEnd`
events, but this seems messier.</del>
---------
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
Co-authored-by: François Mockers <mockersf@gmail.com>
The occlusion culling plugin checks for a GPU feature by looking at
`RenderAdapter`. This is wrong - it should be checking `RenderDevice`.
See these notes for background:
https://github.com/bevyengine/bevy/discussions/18973
I don't have any evidence that this was causing any bugs, so right now
it's just a precaution.
## Testing
```
cargo run --example occlusion_culling
```
Tested on Win10/Nvidia across Vulkan, WebGL/Chrome, WebGPU/Chrome.
# Objective
- The tonemapping example allows using a local image to try out
different color grading. However, using a local file stopped working
when we added the `UnapprovedPathMode` setting to the assets plugin.
## Solution
- Set `unapproved_path_mode: UnapprovedPathMode::Allow` in the example
## Testing
- I tried out the example with local images, previously it would fail
saying it's an untrusted path.
# Objective
Refactor
[`examples/ui/borders.rs`](7f0490655c/examples/ui/borders.rs)
to use the new spawning/hierarchy APIs in 0.16.
## Solution
This refactor reduces the number of `.spawn` calls from about 16 to 2,
using one spawn for each major feature:
* camera2d
* ui layout
The `Children::spawn` relationship API is used to take advantage of
`SpawnIter` for the borders examples in each block.
Each block of examples now returns a Bundle into its respective
variable, which is then used in combination with the new `label` widget
which makes use of the new `impl Bundle` return capability. This allows
the ui layout to use a single `.spawn` with the `children!` macro.
The blocks of examples are still in separate variables because it felt
like a useful way to organize it still, even without needing to spawn at
those locations.
Functionality of the demo hasn't changed, this is just an API/code
update.
## Showcase

<details>
<summary>Before screenshot</summary>

</details>
---------
Co-authored-by: François Mockers <mockersf@gmail.com>
# Objective
Add background colors for text.
Fixes#18889
## Solution
New component `TextBackgroundColor`, add it to any UI `Text` or
`TextSpan` entity to add a background color to its text.
New field on `TextLayoutInfo` `section_rects` holds the list of bounding
rects for each text section.
The bounding rects are generated in `TextPipeline::queue_text` during
text layout, `extract_text_background_colors` extracts the colored
background rects for rendering.
Didn't include `Text2d` support because of z-order issues.
The section rects can also be used to implement interactions targeting
individual text sections.
## Testing
Includes a basic example that can be used for testing:
```
cargo run --example text_background_colors
```
---
## Showcase

Using a proportional font with kerning the results aren't so tidy (since
the bounds of adjacent glyphs can overlap) but it still works fine:

---------
Co-authored-by: Olle Lukowski <lukowskiolle@gmail.com>
Co-authored-by: Gilles Henaux <ghx_github_priv@fastmail.com>
# Objective
Tripped over the `directional_navigation` one recently while playing
around with that example.
Examples should import items from `bevy` rather than the sub-crates
directly.
## Solution
Use paths re-exported by `bevy`.
## Testing
```
cargo run --example log_diagnostics
cargo run --example directional_navigation
cargo run --example custom_projection
```
# Objective
Fixes#18316
## Solution
Add android:configChanges="orientation|screenSize" to the
AndroidManifest.xml as indicated in https://stackoverflow.com/a/3329486
to avoid the GameActivity from getting destroyed, making the app
stuck/crash.
## Testing
I checked the results in my phone and after adding the config change the
issue went away. The change is relatively trivial, so there shouldn't be
the need to make a lot more testing.
The purpose of the scene viewer is to load arbitrary glTF scenes, so
it's inconvenient if they have to be moved into the Bevy assets
directory first. Thus this patch switches the scene viewer to use
`UnapprovedPathMode::Allow`.
---------
Co-authored-by: François Mockers <francois.mockers@vleue.com>
# Objective
The goal of `bevy_platform_support` is to provide a set of platform
agnostic APIs, alongside platform-specific functionality. This is a high
traffic crate (providing things like HashMap and Instant). Especially in
light of https://github.com/bevyengine/bevy/discussions/18799, it
deserves a friendlier / shorter name.
Given that it hasn't had a full release yet, getting this change in
before Bevy 0.16 makes sense.
## Solution
- Rename `bevy_platform_support` to `bevy_platform`.
# Objective
Fixes#16896Fixes#17737
## Solution
Adds a new render phase, including all the new cold specialization
patterns, for wireframes. There's a *lot* of regrettable duplication
here between 3d/2d.
## Testing
All the examples.
## Migration Guide
- `WireframePlugin` must now be created with
`WireframePlugin::default()`.