# Objective
- Fixes#13872 (also mentioned in #17167)
## Solution
- Added conditional padding fields to the shader uniform
## Alternatives
### 1- Use a UVec4
Replace the `u32` field in `MyExtension` by a `UVec4` and only use the
`x` coordinate.
(This was the original approach, but for consistency with the rest of
the codebase, separate padding fields seem to be preferred)
### 2- Don't fix it, unlist it
While the fix is quite simple, it does muddy the waters a tiny bit due
to `quantize_steps` now being a UVec4 instead of a simple u32. We could
simply remove this example from the examples that support WebGL2.
## Testing
- Ran the example locally on WebGL2 (and native Vulkan) successfully
## Objective
Add a test that would have caught #16929 and #18712.
## Solution
The PR adds a `test_invalid_skinned_mesh` example that creates various
valid and invalid skinned meshes. This is designed to catch panics via
CI, and can be inspected visually. It also tests skinned meshes + motion
blur.

The screenshot shows all the tests, but two are currently disabled as
they cause panics. #18074 will re-enable them.
### Concerns
- The test is not currently suitable for screenshot comparison.
- I didn't add the test to CI. I'm a bit unsure if this should be part
of the PR or a follow up discussion.
- Visual inspection requires understanding why some meshes are
deliberately broken and what that looks like.
- I wasn't sure about naming conventions. I put `test` in the name so
it's not confused with a real example.
## Testing
```
cargo run --example test_invalid_skinned_mesh
```
Tested on Win10/Nvidia, across Vulkan, WebGL/Chrome, WebGPU/Chrome.
# Objective
- It's not clear what changes are needed to the shader to convert the
example to 2D.
- If you leave the shader unchanged you get a very confusing error (see
linked issue).
- Fixes#14077
## Solution
A separate example probably isn't needed as there is little difference
between 3D and 2D, but a note saying what changes are needed to the
shader would make it a lot easier.
Let me know if you think it is also worth adding some notes to the rust
file, but it is mostly trivial changes such as changing `Mesh3d` to
`Mesh2d`. I have left the original code in comments next to the changes
in the gist linked at the bottom if you wish to compare.
## Testing
- I just spent a long time working it out the hard way. This would have
made it a lot quicker.
- I have tested the 2D version of the shader with the changes explained
in the suggested comment and it works as expected.
- For testing purposes [here is a complete working 2D
example](https://gist.github.com/nickyfahey/647e2a2c45e695f24e288432b811dfc2).
(note that as per the original example the shader file needs to go in
'assets/shaders/')
# Objective
- nice bevy::camera bevy::mesh bevy::light imports
- skip bevy_light in 2d
## Solution
- add optional crates to internal
- make light only included when building pbr
## Testing
- 3d_scene
# Objective
Fixes#16525Fixes#19710
## Solution
Not allocating a mesh if it is empty.
## Testing
I tested using the following minimum repro from #16525
```rust
use bevy::{asset::RenderAssetUsages, prelude::*, render::mesh::PrimitiveTopology};
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.run();
}
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<ColorMaterial>>,
) {
commands.spawn(Camera2d);
let mesh = Mesh::new(
PrimitiveTopology::TriangleList,
RenderAssetUsages::default(),
);
commands.spawn((
Mesh2d(meshes.add(mesh)),
MeshMaterial2d(materials.add(Color::hsl(180.0, 0.95, 0.7))),
));
}
```
I was able to test on webgl2 and windows native and the issue seems to
be resolved. I am not familiar with how mesh rendering works and feel
like just skipping meshes should cause issues but I did not notice any.
# Objective
- Fixes#19910.
## Solution
- First, allow extraction function to be FnMut instead of Fn. FnMut is a
superset of Fn anyway, and we only ever call this function once at a
time (we would never call this in parallel for different pairs of worlds
or something).
- Run the `RenderStartup` schedule in the extract function with a flag
to only do it once.
- Remove all the `MainRender` stuff.
One sad part here is that now the `RenderStartup` blocks extraction. So
for pipelined rendering, our simulation will be blocked on the first
frame while we set up all the rendering resources. I don't see this as a
big loss though since A) that is fundamentally what we want here -
extraction **has to** run after `RenderStartup`, and the only way to do
better is to somehow run `RenderStartup` in parallel with the first
simulation frame, and B) without `RenderStartup` the **entire** app was
blocked on initializing render resources during Plugin construction - so
we're not really losing anything here.
## Testing
- I ran the `custom_post_processing` example (which was ported to use
`RenderStartup` in #19886) and it still works.
# Objective
- the fast inverse sqrt trick hasnt been useful on modern hardware for
over a decade now
## Solution
- just use sqrt, modern hardware has a dedicated instruction which will
outperform approximations both in efficiency and accuracy
## Testing
- ran `atmosphere`
# Objective
- make lights usable without bevy_render
## Solution
- make a new crate for lights to live in
## Testing
- 3d_scene, lighting, volumetric_fog, ssr, transmission, pcss,
light_textures
Note: no breaking changes because of re-exports, except for light
textures, which were introduced this cycle so it doesn't matter anyways
# Objective
- Calculating gradients in variable-termination loop is bad, and we dont
need to here
## Solution
- Sample mip 0 always
## Testing
- volumetric_fog example
# Objective
- prepare bevy_light for split
- make struct named better
- put it where it belongs
## Solution
- do those things
## Testing
- 3d_scene, lighting
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- prepare bevy_light for split
## Solution
- split render world extract related cluster code from main world ecs
stuff
re-exports make this not breaking
# Objective
- for smallvec some crates specify default features false, other dont.
turns out we dont need them
## Solution
- remove
## Testing
- 3d_scene
# Objective
- prepare bevy_light for split
## Solution
- extract cascade module (this is not strictly necessary for bevy_light)
- clean up imports to be less globby and tangled
- move light specific stuff into light modules
- move light system and type init from pbr into new LightPlugin
## Testing
- 3d_scene, lighting
NOTE TO REVIEWERS: it may help to review commits independently.
# Objective
- Make bevy_light possible by making it possible to split out
clusterable into bevy_camera
## Solution
- move ClusteredDecal to cluster module
- Depends on #19957 (because of the imports shuffling around) (draft
until thats merged)
## Testing
- 3d_scene runs
Note: no breaking changes thanks to re-exports
# Objective
- Make bevy_light possible
## Solution
- Move non-light stuff out of light module (its a marker for whether a
material should cast shadows: thats a material property not a light
property)
## Testing
- 3d_scene runs
# Objective
- Make bevy_light possible
## Solution
- Move some stuff it needs out of somewhere it cant depend on. Plus it
makes sense, cubemap stuff goes next to cubemap stuff.
## Testing
- 3d_scene runs
Note: no breaking changes thanks to re-exports
# Objective
- Make bevy_light possible by making it possible to split out
clusterable into bevy_camera
## Solution
- Move some stuff so i can split it out cleanly.
## Testing
- 3d_scene runs
# Objective
- Make bevy_light possible by making it possible to split out
clusterable into bevy_camera
## Solution
- Move cubemap stuff next to cubemap stuff.
## Testing
- 3d_scene runs
Note: no breaking changes thanks to re-exports
# Objective
- Make bevy_light possible
## Solution
- Move some stuff it needs out of somewhere it cant depend on. Plus it
makes sense, spotlight stuff goes in spotlight file.
## Testing
- 3d_scene runs
Note: no breaking changes thanks to re-exports
# Objective
- Make bevy_light possible by making it possible to split out
clusterable into bevy_camera
## Solution
- Use a resource to store cluster settings instead of recalculating it
every time from the render adapter/device
## Testing
- 3d_scene runs
# Objective
- define scenes without bevy_render
## Solution
- Move Camera2d/3d components out of bevy_core_pipeline
## Testing
- 3d_scene runs fine
Note: no breaking changes thanks to re-exports
# Objective
- Make bevy_light possible
## Solution
- Move some stuff it needs out of somewhere it cant depend on. Plus it
makes sense, visibility stuff goes in visibility.
## Testing
- 3d_scene runs
Note: no breaking changes thanks to re-exports
# Objective
- Progress towards #19887.
## Solution
- Convert `FromWorld` impls into systems that run in `RenderStartup`.
- Move `UiPipeline` init to `build_ui_render` instead of doing it
separately in `finish`.
Note: I am making several of these systems pub so that users could order
their systems relative to them. This is to match the fact that these
types previously were FromWorld so users could initialize them.
## Testing
- Ran `ui_material`, `ui_texture_slice`, `box_shadow`, and `gradients`
examples and it still worked.
# Objective
- get closer to being able to load gltfs without using bevy_render
## Solution
- Split bevy_camera out of bevy_render
- Builds on #19943
- Im sorry for the big diff, i tried to minimize it as much as i can by
using re-exports. This also prevents most breaking changes, but there
are still a couple.
## Testing
- 3d_scene looks good
# Objective
- The usage of ComponentId is quite confusing: events are not
components. By newtyping this, we can prevent stupid mistakes, avoid
leaking internal details and make the code clearer for users and engine
devs reading it.
- Adopts https://github.com/bevyengine/bevy/pull/19755
---------
Co-authored-by: oscar-benderstone <oscarbenderstone@gmail.com>
Co-authored-by: Oscar Bender-Stone <88625129+oscar-benderstone@users.noreply.github.com>
# Objective
- I accidentally left a `register_component_hooks` without actually
adding a hook and didnt notice
## Solution
- mark it must_use so it doesnt happen to other people (maybe this is
just skill issue on me though)
# Objective
- another step towards splitting out bevy_camera, this is needed by
visibility systems
## Solution
- move mesh stuff into mesh place
## Testing
- 3d_scene looks fine
No migration needed because of the re-export, that can be another PR
after i split bevy_camera
# Objective
Move Bevy UI's rendering into a dedicated crate.
Motivations:
* Allow the UI renderer to be used with other UI frameworks than
`bevy_ui`.
* Allow for using alternative renderers like Vello with `bevy_ui`.
* It's difficult for rendering contributors to make changes and
improvements to the UI renderer as it requires in-depth knowledge of the
UI implementation.
## Solution
Move the `render` and `ui_material` modules from `bevy_ui` into a new
crate `bevy_ui_render`.
## Testing
Important examples to check are `testbed_ui`, `testbed_full_ui`,
`ui_material`, `viewport_node` and `gradients`.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
The generated `GetTypeRegistration::get_type_registration` method has an
unnecessary `allow(unused_mut)` attribute. It used to be necessary
because it was possible for `registration` to not be modified, but now
there is always at least one modification.
## Solution
Remove the attribute.
## Testing
I checked the `cargo expand` output.
# Objective
```
2025-07-03T11:48:34.039501Z ERROR panic: thread 'IO Task Pool (6)' panicked at 'byte index 9 is not a char boundary; it is inside '个' (bytes 7..10) of `展示_个人收款码.png`': [...]\crates\bevy_asset\src\path.rs:475
```
## Solution
char_indices
Adds support for:
- `WGPU_ADAPTER_NAME` which will attempt to select a specific adapter
with a given name.
- `WGPU_FORCE_FALLBACK_ADAPTER` which will force fallback to a fallback
(software) renderer, if available.
The first has higher specificity than the second.
# Objective
Allow combinator and pipe systems to delay validation of the second
system, while still allowing the second system to be skipped.
Fixes#18796
Allow fallible systems to be used as one-shot systems, reporting errors
to the error handler when used through commands.
Fixes#19722
Allow fallible systems to be used as run conditions, including when used
with combinators. Alternative to #19580.
Always validate parameters when calling the safe
`run_without_applying_deferred`, `run`, and `run_readonly` methods on a
`System`.
## Solution
Have `System::run_unsafe` return a `Result`.
We want pipe systems to run the first system before validating the
second, since the first system may affect whether the second system has
valid parameters. But if the second system skips then we have no output
value to return! So, pipe systems must return a `Result` that indicates
whether the second system ran.
But if we just make pipe systems have `Out = Result<B::Out>`, then
chaining `a.pipe(b).pipe(c)` becomes difficult. `c` would need to accept
the `Result` from `a.pipe(b)`, which means it would likely need to
return `Result` itself, giving `Result<Result<Out>>`!
Instead, we make *all* systems return a `Result`! We move the handling
of fallible systems from `IntoScheduleConfigs` and `IntoObserverSystem`
to `SystemParamFunction` and `ExclusiveSystemParamFunction`, so that an
infallible system can be wrapped before being passed to a combinator.
As a side effect, this enables fallible systems to be used as run
conditions and one-shot systems.
Now that the safe `run_without_applying_deferred`, `run`, and
`run_readonly` methods return a `Result`, we can have them perform
parameter validation themselves instead of requiring each caller to
remember to call them. `run_unsafe` will continue to not validate
parameters, since it is used in the multi-threaded executor when we want
to validate and run in separate tasks.
Note that this makes type inference a little more brittle. A function
that returns `Result<T>` can be considered either a fallible system
returning `T` or an infallible system returning `Result<T>` (and this is
important to continue supporting `pipe`-based error handling)! So there
are some cases where the output type of a system can no longer be
inferred. It will work fine when directly adding to a schedule, since
then the output type is fixed to `()` (or `bool` for run conditions).
And it will work fine when `pipe`ing to a system with a typed input
parameter.
I used a dedicated `RunSystemError` for the error type instead of plain
`BevyError` so that skipping a system does not box an error or capture a
backtrace.
...which previously used a HashSet, whos iter has no ordering guarantee
fixes#19687
i also discovered that the asserted order in the unit test is reversed,
so i fixed that. I dont know if that reversed order is intentional
Edit: i referenced the wrong issue oops
# Objective
- First step towards #279
## Solution
Makes the necessary internal data structure changes in order to allow
system removal to be added in a future PR: `Vec`s storing systems and
system sets in `ScheduleGraph` have been replaced with `SlotMap`s.
See the included migration guide for the required changes.
## Testing
Internal changes only and no new features *should* mean no new tests are
requried.
- renamed `spec_v2` related modules, that commit slipped through the
other pr #17373
- revised struct and trait docs for clarity, and gave a short intro to
specialization
- turns out the derive macro was broken, fixed that too
# Objective
Current implementation of `Sprite::compute_pixel_space_point` always
returns the sprite centre as an `Ok` point when the `custom_size` is set
to `Vec2::ZERO`. This leads to unexpected behaviour. For example, it
causes these sprites to block all interactions with other sprites in the
picking backend (under default settings). This small PR:
- Fixes sprite pixel space point computation for sprites with zero
custom_size
- Resolves issue #19880.
## Solution
We handle the zero custom_size case explicitly and return
`Err(point_relative_to_sprite_center)` instead of
`Ok(point_relative_to_texture)`.
## Testing
Implemented a new test for zero custom_size sprites within the
`bevy_sprite::sprite` module. Also verified that the example from issue
#19880 is behaving as expected.
No further testing is required.
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
Can run the simple application example from the linked issue. Or
evaluate the implemented test.
---------
Co-authored-by: James Lucas <jalucas@nvidia.com>
## Objective
Add a test that reproduces #11111 (and partially #18267). The bug is
that asset loader settings are effectively ignored if the same asset is
loaded multiple times with different settings.
## Solution
Add a unit test to `bevy_assets/lib.rs`. The test will be marked as
`#[ignore]` until #11111 is fixed.
```rust
// Load the same asset with different settings.
let handle_1 = load(asset_server, "test.u8", 1);
let handle_2 = load(asset_server, "test.u8", 2);
// Handles should be different.
assert_ne!(handle_1, handle_2);
```
## Concerns
I'm not 100% sure that the current behaviour is actually broken - I
can't see anything in the asset system design docs that explicitly says
different settings should create different asset ids.
UPDATE: Sentiment from issue comments and discord varies between "bug"
and "undesirable consequence of design decisions, alternatives should be
explored". So I've concluded that the test is valid and desirable.
## Testing
```sh
cargo test -p bevy_asset --features multi_threaded
# Or to repro the issue:
cargo test -p bevy_asset --features multi_threaded -- --ignored
```
# Objective
- Progress towards #19887.
## Solution
- Rewrite the FromWorld impls to systems that create the pipeline
resources.
## Testing
- Ran the `anti_aliasing` example and it still works.