Commit Graph

55 Commits

Author SHA1 Message Date
Luo Zhihao 0d00c9109f Fix nightly clippy and clippy::result_large_err again (#24624)
# Objective

#24206 boxes the large error in `GltfError` but it's not sufficient
after https://github.com/rust-lang/rust-clippy/issues/17070 is fixed.

## Solution

Box `AssetLoadError::RequestedHandleTypeMismatch` so that it is reduced
to 120 bytes which is below 128 bytes.

Also fix some other trivial clippy warnings.

## Testing

Use the latest nightly clippy which has
https://github.com/rust-lang/rust-clippy/issues/17070 fixed:
```
cargo +nightly clippy --workspace --all-features --all-targets -- -D warnings
```
2026-06-17 04:40:59 +00:00
bytemuck df5d238c6d Change From<&str> to From<&'static str> for Name (#24544)
# Objective

- Fixes #24465

## Solution

- Changed `impl From<&str> for Name` to `impl From<&'static str> for
Name`

## Testing

- The only place it is (the From<&str> implementation) used is on this
test, line 1752, which still passes:
https://github.com/bevyengine/bevy/blob/5d5e3f9551ca57a228cf49912df1663f05a037c2/crates/bevy_animation/src/lib.rs#L1722-L1762
2026-06-11 17:42:23 +00:00
ickshonpe 457b91808a More consistant Font asset resolution and change detection (#24362)
# Objective

- When `FontSource` resolution fails because an asset isn't yet loaded,
it doesn't attempt to reresolve the `FontSource` again the next frame.
- When a `Font` asset is removed, its font data is not unloaded from
Parley's font database
- The results from font lookups can be inconsistant when using `Handle`s
to identify a font.

Fixes #24356

## Solution

* In `load_font_assets_into_font_collection`, register each font twice,
once with an internal asset-specific alias for handle lookups and once
using its embedded family name.
* Use `set_changed` on `TextFont` to trigger chain detection, instead of
the `needs_rerender` flag on `TextBlock`. Schedule
`load_font_assets_into_collection` to run before
`detect_text_needs_rerender`, otherwise this would delay updates for a
frame.
* Store the changed family ids and asset paths, and set any `TextFont`s
that refer to them as changed.
* Don't update the measure funcs in `update_editable_text_content_size`
on font asset changes. Instead rely on the narrower `TextFont` change
detection, which is sufficient now because
`load_font_assets_into_font_collection` marks affected `TextFont`
components as changed when newly loaded font assets can affect font
resolution.
* Removed the mutable deref of `EditableText` at the start of
`update_editable_text_styles`. The editor is only mutable accessed if
updates to the styles need to be made.
* On unloading a font rebuild the whole font database, minus the
unloaded fonts, remap any generic families and relayout all text.
* Keep a copy of the registered generic families in `FontCx`, so they
can be remapped after unloading a font.

## Testing

```rust
use bevy::{
    feathers::{controls::FeathersNumberInput, FeathersPlugins},
    prelude::*,
};

fn main() {
    App::new()
        .add_plugins((DefaultPlugins, FeathersPlugins))
        .add_systems(Startup, setup)
        .add_systems(Update, spawn_number_input)
        .run();
}

fn setup(mut commands: Commands) {
    // ui camera
    commands.spawn(Camera2d);
}

fn spawn_number_input(mut commands: Commands, mut is_spawned: Local<bool>) {
    if *is_spawned {
        return;
    }
    *is_spawned = true;
    commands.spawn_scene(bsn! {
        Node {
            margin: UiRect::all(auto())
        }
        Outline
        Children [
        :FeathersNumberInput Node { width: px(200) }
        ]
    });
}
```

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2026-06-04 04:55:04 +00:00
Luo Zhihao 89cbe86900 Fix shader import errors in deferred, solari and meshlet (#24520)
# Objective

Fixes regression from #21926

## Solution

Fixes shader import errors

## Testing

Tested deferred_rendering, atmosphere and meshlet examples.
2026-06-03 16:05:30 +00:00
Kevin Reid 163bec99f1 Remove interner_name argument from define_label! and make the interner private. (#24445)
# Objective

Simplify the use of `define_label!()`.

## Solution

- Move the `static` interner inside the `intern()` method, so that it is
not visible anywhere else and does not need to have a non-conflicting
name. The only operation the interner has is interning, so the
`intern()` trait method is all the access that is ever needed.
- Also added support for trailing commas.

This PR will conflict with #24444. I will rebase whichever one doesn’t
get merged first.

## Testing

- Ran tests with `cargo run -p ci -- --keep-going test`. There were some
failures that I believe are existing/spurious.
2026-06-02 18:35:37 +00:00
Luo Zhihao 7517c61ecd Add options to lower precision/compressed vertex buffer (#21926)
# Objective

Resolves #21902.

## Solution

This PR adopts a relatively transparent approach to reduce the GPU
vertex buffer size. On CPU-side mesh can still use uncompressed Float32
data, and users are not required to insert compressed vertex formats.
The vertex data is automatically processed into
lower-precision/octahedral encoded data when uploading to the GPU.

To enable vertex attribute compression, just set the
`attribute_compression` field of Mesh, or set
`mesh_attribute_compression` of GltfLoaderSettings. If enabled, normal
and tangent will be octahedral encoded Unorm16x2, uv0, uv1, joint weight
and color will be corresponding Unorm16 or Float16. I also provide
Unorm8x4 for vertex color if hdr isn't needed.

Update 2026-2-16

Removed previous approach that automatically compresses vertex buffer
according to flags when uploading to GPU. Instead, I added
`compressed_mesh` method to Mesh to construct compressed Mesh ahead of
time. GltfLoader can also opt-in mesh compressing when loading. I also
add an option to convert indices to u16, though I believe blender gltf
exporter already uses u16 indices when possible.


## Testing

Run `many_cubes`, `many_foxes`, `many_morph_targets` with
`--vertex-compression` to test 3d.
Run `bevymark` with `sprite_mesh` to test 2d, because `SpriteMesh` uses
compressed quad mesh now.

---------

Co-authored-by: Greeble <166992735+greeble-dev@users.noreply.github.com>
2026-06-02 03:22:56 +00:00
Luo Zhihao 1d69b9d7db Box large variants in some Errors to reduce size and avoid clippy::result_large_err (#24206)
# Objective

Resolve `#[expect(clippy::result_large_err)]`.

## Solution

Box large variants in `GltfError` and `LoadDirectError` to reduce their
size. `GltfError` is reduced to 64 bytes and `LoadDirectError` is
reduced to 80 bytes.

## Testing

CI

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2026-06-02 00:21:24 +00:00
Daniel Skates 0a57f42e16 Generalise TemporaryRenderEntity over AppLabel (#24419)
# Objective

- Step towards making the extract infra is reusable for non-rendering
crates (see https://github.com/bevyengine/bevy/issues/24483 )

## Solution

- Replace `TemporaryRenderEntity` with a generic over `AppLabel`,
`TemporaryRenderEntity` becomes an alias over `RenderApp`

## Testing

- CI
- `cargo run --example animated_mesh`
2026-06-02 00:20:15 +00:00
Greeble bcabd3861d Reduce size of Typed::type_info() (#24171)
## Objective

Change the generated code for `Typed::type_info()` to reduce release
build binary sizes by ~4.6MB. Also makes some very minor improvements to
runtime memory and compile times.

## Background

Say I have this reflected struct:

```rust
#[derive(Reflect)]
struct Example {
    number: u32,
    length: f32,
}
```

The generated code for `Example::type_info` is:

```rust
impl bevy_reflect::Typed for Example {
    fn type_info() -> &'static bevy_reflect::TypeInfo {
        static CELL: bevy_reflect::utility::NonGenericTypeInfoCell =
            bevy_reflect::utility::NonGenericTypeInfoCell::new();
        CELL.get_or_set(|| {
            bevy_reflect::TypeInfo::Struct(bevy_reflect::structs::StructInfo::new::<Self>(
                &[
                    bevy_reflect::NamedField::new::<u32>("number"),
                    bevy_reflect::NamedField::new::<f32>("length"),
                ],
            ))
        })
    }
}
```

So on the first call it creates a bunch of data structures that
represent the type (`StructInfo`, `NamedField` etc), and later calls
just return a reference to that data.

The assembly code for `type_info` can be surprisingly large -
`Example::type_info` is 2KB (x86, release). This might not sound like
much, but it adds up when there's over a thousand reflected types, and
some of them are much more complex - the assembly for
`bevy_ui::Node::type_info` is 26.5KB. In total there's several megabytes
depending on build settings (it's hard to be completely accurate due to
inlining and the way some things are hidden behind closures).

## Solution

This PR makes a few different changes to the generated code for
`type_info` and various supporting code. In a release build,
`Example:type_info` goes from 2KB to 126 bytes, and
`bevy_ui::Node::type_info` from 26.5KB to 10.1KB. The binary goes from
79.03MB to 74.38MB (-4.64MB, -5.9%).

### 1. Avoid allocations

Several structs contain an `Arc<CustomAttributes>`. But most types
doesn't have any custom attributes. Switching to
`Option<Arc<CustomAttributes>>` avoids allocating an `Arc` for the empty
case.

```diff
 pub fn new(name: &'static str) -> Self {
     Self {
         name,
-        custom_attributes: Arc::new(CustomAttributes::default()),
+        custom_attributes: None,
         #[cfg(feature = "reflect_documentation")]
         docs: None,
     }
```

(**EDIT:** After feedback this approach was changed slightly - see
https://github.com/bevyengine/bevy/pull/24171#issuecomment-4506875895.)

Similarly, `Generics` is a `Box<[GenericInfo]>` that's usually empty. 

```diff
-pub struct Generics(Box<[GenericInfo]>);
+pub struct Generics(Option<Box<[GenericInfo]>>);
```

(**EDIT:** A reviewer noted that an empty boxed slice does not allocate.
However, the change still decreases binary size. For details:
https://github.com/bevyengine/bevy/pull/24171#discussion_r3207800618.)

### 2. Reduce generic code

`StructInfo::new` and others look roughly like this:

```rust
pub fn new<T: Reflect + TypePath>(fields: &[NamedField]) -> Self {
    ...build internal boxes and HashMaps...
    
    Self {
        ty: Type::of::<T>(),
        fields: fields.to_vec().into_boxed_slice(),
        ...
    }
}
```

Being generic means that the whole function gets duplicated for each
unique `T`, and often gets inlined too. But `T` is only used once by
`Type::of::<T>()`.

This PR splits the function into a small generic stub that calls a
larger non-generic with `inline(never)`.

```rust
pub fn new<T: Reflect + TypePath>(fields: &[NamedField]) -> Self {
    Self::from_erased(Type::of::<T>(), fields)
}
    
#[inline(never)]
pub fn from_erased<T: Reflect + TypePath>(fields: &[NamedField]) -> Self {
    ...
}
```

### 3. Reduce inlining

I've also made a few changes to inlining on `type_info`:

```diff
 impl bevy_reflect::Typed for Example {
-    #[inline] 
+    #[inline(never)] 
     fn type_info() -> &'static bevy_reflect::TypeInfo {
         static CELL: bevy_reflect::utility::NonGenericTypeInfoCell =
             bevy_reflect::utility::NonGenericTypeInfoCell::new();
-        CELL.get_or_set(|| {
+        CELL.get_or_set(#[inline(never)] || {
             ...
```

The first change might be contentious as it makes
`get_represented_type_info` +20% slower in micro-benchmarks - although
20% slower only means one cycle slower. I'd guess that's worth it to
save ~363KB - it might even be a performance increase in real code due
to memory latency. But it's debatable - I'd be fine to remove it.

The second change avoids inlining the closure since it can only be
called once - this gives a ~330KB saving with no performance cost.
Although I'm not quite sure *why* it's a saving. I suspect that non-LTO
release builds are ending up with two copies - one regular closure and
one inlined copy.

### Putting it all together

Here's the cumulative effect of each change on a release build of
`3d_scene` (Win10, x86).

| | |
|-|-|
| Original | 80,927KB |
| Change `Arc<CustomAttributes>` to option | 78,185KB (-2,742KB) |
| Change `Generics` to option | 77,959KB (-226KB) |
| Change `TypeInfo` variants to reduce generics | 76,866KB (-1,093KB) |
| Never inline `type_info` inner closure | 76,536KB (-330KB) |
| Never inline `type_info` itself | 76,173KB (-363KB) |

Compile times maybe went down a second or two (2m21s -> 2m19s), although
I'm not sure how much to trust that.

And the before/after on a few different builds:

| Build | Before | After | Difference
|-|-|-|-|
| x86 release | 79.0MB | 74.3MB | -4.7MB, -5.9% |
| x86 release optimized | 45.3MB | 43.9MB | -1.4MB, -3% |
| WASM release | 90.3MB | 88.7MB | -1.6MB, -1.7%) |
| WASM release optimized | 61.5MB | 60.6MB | -0.9MB, -1.5% |

The optimized build has `codegen-units = 1, lto = "fat", panic =
"abort"`.

## Can More Be Done?

Yes, I can imagine a bunch more ways to make `type_info` smaller. This
PR only does the easy stuff. But all the options I could think of are
more complex, and there will be diminishing returns.

The dream would be to make `TypeInfo` entirely `const` data. But that's
a major overhaul and might mean requiring it to leak memory - that's
fine for static reflection, but I don't know if it's also used where
leaking would be problematic.

A less drastic option would involve changing `type_info` to not use
`StructInfo`/etc directly - instead it would build up a bunch of smaller
POD types that don't need much copying and never need to free memory.
Then finally it would pass this simpler type to a non-inlined function
that actually creates the real `TypeInfo`. Would that be worth it? It
adds a lot of code, and there's a risk that the savings might be just a
few hundred KB.

## Testing

```sh
cargo test -p bevy_reflect
cargo test -p bevy_reflect_derive
cargo test -p bevy_asset
cargo run --example custom_attributes

# Benchmark type_info
cargo bench -p benches --bench reflect -- concrete_struct_type_info
```

---------

Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
2026-06-01 23:48:42 +00:00
Greeble 3cc7161f5f Deprecate AssetId::invalid() (#24392)
## Objective

Progress #19024 (removing UUID handles). Even if UUID handles end up
sticking around, there's an argument for deprecating
`AssetId::invalid()` in the name of simplicity and robustness.

## Solution

Remove the last remaining case of `AssetId::invalid()` in the
`custom_phase_item` example. The example only used it as a placeholder
value, so `AssetId::default()` is fine.

```diff
 Opaque3dBinKey {
-    asset_id: AssetId::<Mesh>::invalid().untyped(),
+    asset_id: AssetId::<Mesh>::default().untyped(),
 }
```

## Testing

```sh
cargo run --example custom_phase_item
```
2026-05-23 15:20:34 +00:00
Steve Sloan 1e2aa7c578 Fix atmosphere not allowing multiple cameras (#23113)
# Objective

Allow multiple cameras to render an atmosphere enabling split screen and
VR apps to use the feature

## Solution

Use iter().next() instead of single() for when multiple Atmosphere
entities exist

## Testing

Tested this by adding a second camera to the atmosphere example.
Tested it in VR with the bevy_oxr crate
2026-05-22 15:01:55 +00:00
François Mockers 03f16a4a5a clear 0.19 release content from main (#24276)
# Objective

- 0.19 branch has started, clear release content on main

## Solution

- clear release content on main
2026-05-22 12:18:40 +00:00
Gino Valente d38a00ff8c bevy_reflect: Allow parameters to be passed to type data (#13723)
# Objective

Addresses
[comments](https://github.com/bevyengine/bevy/pull/7317#issuecomment-2143075852)
regarding #7317 (note that this doesn't replace #7317, there are still
some great improvements there besides this syntactical problem).

There currently exist some "special" type data registrations that can be
registered like other type data (e.g. `#[reflect(Hash)]`) or can use a
"special" syntax to allow specifying custom implementations (e.g.
`#[reflect(Hash(custom_hash_fn))]`). And there may be more to follow
(#13432).

What's interesting is that most of these special cased registrations
don't actually come with any type data type. Instead, they simply modify
methods on `Reflect` (e.g. `Reflect::reflect_hash`).

#7317 sought to distinguish between these "special" registrations by
making them lowercase and use a more conventional attribute style:
`#[reflect(hash = "custom_hash_fn")]`.

However, while this did help distinguish these registrations and make
them a bit prettier, they now require the user to actually know which
traits are "special" and which are not (as pointed out
[here](https://github.com/bevyengine/bevy/pull/7317#issuecomment-2143075852)).

Ideally, users shouldn't have to know which traits are "special" until
they need to. For most users, they should just know that they need to
register their trait in order for certain things to work. And the
special-casing may be easier to follow if we open up the configuration
abilities to _all_ type data.

## Solution

This PR introduces `CreateTypeData` which replaces `FromType`. This was
done for two reasons.

Firstly, `FromType` isn't very descriptive as to what it should be used
for. We are creating type data from a type, but it's not immediately
clear this is even for type data. Renaming to `CreateTypeData` should
hopefully make this much clearer.

Secondly, in order to support type data with parameters like the
`custom_hash_fn` in `reflect(Hash(custom_hash_fn))`, an additional
`Input` type parameter had to be added. This makes the new signature
`CreateTypeData<T, Input = ()>`.

We can now create type data that accepts input!

```rust
trait Combine {
  fn combine(a: f32, b: f32) -> f32;
}

#[derive(Clone)]
struct ReflectCombine {
  multiplier: f32,
  additional: f32,
  combine: fn(f32, f32) -> f32,
}

impl ReflectCombine {
  pub fn combine(&self, a: f32, b: f32) -> f32 {
    let combined = (self.combine)(a, b);
    let multiplied = self.multiplier * combined;
    multiplied + self.additional
  }
}

impl<T: Combine + Reflect> CreateTypeData<T, (f32, f32)> for ReflectCombine {
  fn create_type_data(input: (f32, f32)) -> Self {
    Self {
      multiplier: input.0,
      additional: input.1,
      combine: T::combine,
    }
  }
}
```

And then register them with the special function-like syntax:

```rust
#[derive(Reflect)]
#[reflect(Combine(2.0, 4.0))]
struct Foo;
```

The above code will compile into the following registration:

```rust
registration.insert(<ReflectCombine as CreateTypeData<Self, _>>::create_type_data((2.0, 4.0)))
```

Notice how the macro automatically generates the tuple for us, so we
don't have to add an additional layer of parentheses.

### Multiple Input Types

You might be wondering why we're using a type parameter instead of an
associated type to specify the input type.

An associated type would limit us to a single implementation. This means
that if we want to support the type data with optional parameters (e.g.
support both `Hash` and `Hash(custom_hash_fn)`), then all type data must
take in `Option<Self::Input>`, regardless of whether or not a `None`
case is supported.

This is important because the macro has to be pass in _something_,
whether that be `()` or `None`.

By using a type parameter we open the door to type data with required
input:

```rust
// `ReflectMyTrait` must be registered with input
impl<T> CreateTypeData<T, u32> for ReflectMyTrait {
  fn create_type_data(input: u32) -> Self {
    Self {
      value: input,
    }
  }
}

// And we can support all different input types
impl<T> CreateTypeData<T, i32> for ReflectMyTrait {
  fn create_type_data(input: i32) -> Self {
    Self {
      value: input.abs() as u32,
    }
  }
}
```

However, this may be something we don't necessarily care about since
users could also get away with this using custom input enums. And the
required-input case could be deferred until runtime (i.e. maybe a panic
in the `None` case).

### Adding `ReflectPartialEq` and `ReflectHash`

I had originally considered adding `ReflectPartialEq` and `ReflectHash`
type data to further decrease the differences between the "special"
registrations and the regular ones. However, I chose not to do that to
(1) reduce the complexity of this PR and (2) we may end up removing
these entirely due to #8695.

### What else is this good for?

Another question you might have is what else this is good for beyond
just making things a bit more consistent.

I'm not sure exactly how the community will use it, but I can see it
being used for things like feature gating certain functionality:

```rust
#[derive(Reflect)]
#[cfg_attr(feature = "debug", reflect(MyTrait(true)))]
#[cfg_attr(not(feature = "debug"), reflect(MyTrait(false)))]
struct Foo;
```

Or to emulate specialization via reflection:

```rust
impl<T> DoSomething for T {
  fn do_something(&self) {
    println!("Doing the same old stuff.");
  }
}

#[derive(Reflect)]
#[reflect(ReflectDoSomething(|_| {
  println!("Doing something special!");
}))]
struct Foo;
```

Note that all of the above could always be done with manual
registration. However, due to them requiring input, some cases could
_only_ be done with manual registration.

This PR mainly opens the door to doing more of this interesting stuff
with type data via the macro registration. It not only unifies "special"
and regular registrations, but also manual and automatic registrations.

## Testing

The tests for this feature are split into doctests (for the docs on
`CreateTypeData`) and in the compile-fail tests.

These will both be verified automatically by CI.

---

## Changelog

- Replaced `FromType<T>` with `CreateTypeData<T, Input = ()>`
- Type data may now opt-in to accepting input during creation using the
`#[reflect(MyTrait(...))]` syntax
- Added `TypeRegistry::register_type_data_with` method

## Migration Guide

`FromType<T>` has been replaced by `CreateTypeData<T, Input = ()>`.
Implementors of `FromType<T>` will need to update their implementation:

```rust
// BEFORE
impl<T> FromType<T> for ReflectMyTrait {
  fn from_type() -> Self {
    // ...
  }
}

// AFTER
impl<T> CreateTypeData<T> for ReflectMyTrait {
  fn create_type_data(input: ()) -> Self {
    // ...
  }
}
```

Additionally, any calls made to `FromType::from_type` will need to be
updated as well:

```rust
// BEFORE
<ReflectMyTrait as FromType<Foo>>::from_type()

// AFTER
<ReflectMyTrait as CreateTypeData<Foo>>::create_type_data(())
```
2026-05-21 09:49:51 +00:00
urben1680 1413bc4e36 Add TextLayout constructor rename migration guide, fix Access deprecation messages (#24286)
Two minor things I noticed during migrating for 0.19-rc1.
2026-05-20 22:45:49 +00:00
Kevin Chen f9c4629a81 Specify where RenderGraph is in Migration Guide, add it to bevy_render::prelude (#24265)
# Objective

- Fixes #24257

## Solution

- `RenderGraph` is already pub, but it moved locations. Specify where in
the migration guide.
- Added `RenderGraph` to `bevy_render`’s prelude. This can be removed if
desired.

## Testing

- ci
2026-05-13 06:38:41 +00:00
Kevin Chen 0725f26533 Add migration guide for shadow_pass split (#24262)
# Objective

- Fixes #24256 

## Solution

- Adds the migration guide

## Testing

- CI will let me know if it’s formatted incorrectly
2026-05-12 23:00:10 +00:00
François Mockers a54882cc98 Cleanup release content (one more time) (#24198)
# Objective

- Migration guide merged in release-content

## Solution

- Move it
- Add a CI check that will block new merges

Opened PRs that sill change that folder:
- #23467
- #23445
- #23373
- #23137
- #23132
- #23056
- #22917
- #22852
- #22782
- #22670
- #22557
- #22500
- #21929
- #21912
- #21897
- #21893
- #21890
- #21889
- #21839
- #21811
- #21772

None of them are likely to be merged in the 0.19
2026-05-08 18:13:00 +00:00
Mira ae2fcc0353 Resource hooks & immutable resources (#24164)
# Objective

Enables the resource derive macro to specify the attributes for
- hooks (fixes #24159)
- immutability (fixes #24166)

Also fixes `resource_scope` overwriting change ticks and a few related
doc comments.

## Showcase

```rust
#[derive(Resource)]
#[component(immutable)]
#[component(on_insert = update_level, on_discard = update_level)]
struct Level(i32);
```
2026-05-08 13:33:09 +00:00
Luo Zhihao eaa8d42f60 Store view environment map rotation in LightProbesUniform and remove EnvironmentMapUniform (#24095)
# Objective

Fixes
https://github.com/bevyengine/bevy/issues/24084#issuecomment-4365309756
Also fixes `EnvironmentMapLight::rotation` if it is attached to a view.

## Solution

Store view environment map rotation in `LightProbesUniform` and remove
`EnvironmentMapUniform`

## Testing

The examples works:
```
cargo r --example pccm --features free_camera,https
cargo r --example light_probe_blending --features free_camera,https
cargo r --example rotate_environment_map --features pbr_multi_layer_material_textures
```
2026-05-06 16:58:16 +00:00
Trashtalk217 07fc18c39f Editting pass over migration guides (#24155)
# Objective

Get ready for a release.

On a personal note, this is a lot easier than doing a showcase pass, as
I really don't know how to hit the right tone for that.
2026-05-06 15:28:25 +00:00
Alice Cecile 74e7f1dd14 Integrate bevy_world_serialization rename into existing release content (#24110)
# Objective

An existing migration guide + release note got clobbered by the
`bevy_scene` -> `bevy_ecs_serialization` rename.

Fixes #24007.

## Solution

Carefully integrate the rename into the text to make the migration less
confusing.
2026-05-04 01:44:01 +00:00
Alice Cecile ba7b3c8950 Rename bevy_experimental_feathers feature to bevy_feathers (#24108)
# Objective

> With the introduction of scene components, the feathers API has now
reached its final form. This has a number of consequences:
> - There's no longer any reason to keep the experimental flag around
> - The effort of migrating the Bevy examples to feathers widgets is
unblocked, however I think we should start with migrating just one
example


- @viridia 

## Solution

1. Rename the feature flag.
2. Write a migration guide.

This was previously attempted as part of
https://github.com/bevyengine/bevy/pull/22934, but I got pushback there.
Now that bsn! is more complete (scene components!) things are better.

I've opted not to change the default features here, even though it makes
it much harder to move our examples over, because that's a much more
contentious change. While I feel that Bevy's default features should be
example-oriented, that's still up for debate!
2026-05-03 23:53:51 +00:00
Luo Zhihao 6fcf9a6dcc Create mesh view bind group layout on demand to remove unused bindings (#23982)
# Objective

Fixes #23627.

`MeshPipelineViewLayoutKey` uses too many bindings even if features like
ssr, environment map are unused.

## Solution

Don't pre-allocate every combination that grows exponentially. Instead,
create mesh view bind group layout on demand so that we can add more
view keys to reduce unused bindings.

`MeshPipelineViewLayouts::get_view_layout` will be slower, but I'm not
sure how slow it is. My feeling is that the overhead is not high,
compared to when we clone it before.

## Testing

```
WGPU_SETTINGS_PRIO=webgl2 cargo r --example 3d_scene
cargo r --example ssr --features bluenoise_texture
cargo r --example ssao
cargo r --example irradiance_volumes
```

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
2026-05-01 21:08:28 +00:00
Christian Oelschlegel f6ff3c334e Remove android game activity from default (#23708)
android handle only one activity, either game or native. To use native,
the default could now be used, but all other android need to add the
game activity.

# Objective

android native activities should be able to use the default

## Solution

remove android-game-activity from default

## Testing

created a default app for android native activity with default

## Important

Will be a breaking change for apps using android-game-activity.

---------

Co-authored-by: Christian Oelschlegel <oelschle@sciphy.de>
Co-authored-by: leomeinel <leo@meinel.dev>
2026-04-28 20:39:04 +00:00
andriyDev e9e15e516c Replace the NestedLoader API with NestedLoadBuilder (matching LoadBuilder). (#23979)
# Objective

- Followup to #23663.
- Make the nested loading API easier to understand (when reading from
docs.rs).

## Solution

- Remove the type-state stuff from `NestedLoader`. Make each way of
calling load just be its own function.
- Add override_unapproved to the `NestedLoader`.
- Rename `NestedLoader` to `NestedLoadBuilder` (to match `LoadBuilder`).
- Rename `.loader()` to `.load_builder()` just like
`AssetServer::load_builder`.

Some decisions:

- I included `override_unapproved` to match LoadBuilder. We could remove
this to say "loaders shouldn't be able to override", but I don't think
that's problematic, and I'd rather have it for completeness.
- I omitted `with_guard` from `NestedLoadBuilder`. This option doesn't
really make sense, plus you could just use the async methods to do this
instead.
- Since we omitted the `with_guard` (since it really doesn't make sense
in this context), I decided not to reuse `LoadBuilder` in any way here.
Either way, we need to deal with dependencies, so we couldn't just use
it directly anyway.
- I just created all 9 load variants as separate methods. That's a lot
compared to the 4 variants in LoadBuilder. We could reduce it to 6 load
variants, if we kept the `with_reader` stuff as a type-state like we did
with `NestedLoader`. I'm not a fan of how many variants we have, but I
don't think there's a way to do this without opening up impossible
configurations, like doing with_reader for a deferred call - this
doesn't work!
2026-04-28 05:13:40 +00:00
Luo Zhihao e2d96accc5 Allow configuring fullscreen material system order (#23786)
# Objective

Fixes #23781

When Hdr is on, the order of `tonemapping` and
`fullscreen_material_system` is uncertain and the result of main pass
can be cleared. `run_in` `run_before` `run_after` can only specify
system set and can't specify a specific system and them hardcode
`Core3dSystems`.

## Solution

Replace `run_in` `run_before` `run_after` with `fn
schedule_configs(system: ScheduleConfigs<BoxedSystem>) ->
ScheduleConfigs<BoxedSystem>`

## Testing

Run fullscreen_material example with Hdr
2026-04-28 04:58:26 +00:00
Luo Zhihao 76c9576c61 Rename WgpuSettingsPriority::Compatibility to WgpuSettingsPriority::WebGPU (#23783)
# Objective

Closes #23033

## Solution

Rename `Compatibility` to `WebGPU` for clarity.

## Testing

/

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2026-04-27 02:27:56 +00:00
charlotte 🌸 8930a157fd Fixes for camera output swap chain acquisition and view target rendering (#23959)
We discovered in Processing when using GLFW as a windowing backend that
sometimes a window is reported as occluded for the first several frames.
When a camera is configured with `ClearColorConfig::None`, this can be
problematic as the first several frames are skipped and thus do not
accumulate drawing state in the `ViewTarget` texture. In general, when
the user requests a color attachment with `Load` semantics, we should do
our best to make sure that we write into that texture, as
missing/dropped frames my result in visually incorrect output.

A few related fixes:
1. Make `out_texture` and `Option` in `ViewTarget`. A valid render
target texture is *not* required in order to render if the user has
requested view target `Load` semantics. We still skip rendering when the
user has requested `Clear` as this output will be overwritten anyway,
saving some energy (i.e. preserves the previous behavior).
2. Skip acquiring the swapchain if no camera is configured to
`CameraOutputMode::Write` to a swapchain. This should help avoid
weirdness where we acquire but don't do work on a swapchain texture.
2026-04-25 04:45:51 +00:00
Talin 8d52bccfa3 Move stray release-content into the correct location. (#23961)
Fixes #23631

Closes #23638.
2026-04-23 23:34:36 +00:00
Alice Cecile 8623d29a7a Remove Core prefix from remaining UI widget components (#23938)
# Objective

This prefix was ruled unhelpful, and we previously removed it from most
of our types.

We missed a few apparently (spotted in #23924).

## Solution

Find and replace + update the migration guide.
2026-04-22 19:56:27 +00:00
Sieluna c7f2038d09 Align bevy_transform's feature flags (#23919)
# Objective

`bevy_transform`'s multi-threading behavior was previously gated on
`feature = "std"`, which incorrectly conflated standard library
availability with multi-threading capability. This means:

- Users who enabled `no_std` but had multi-threading available lost
parallelism unintentionally.
- Users who had `std` but wanted single-threaded execution (e.g. WASM)
still attempted to use the parallel path.
- `bevy_internal`'s `multi_threaded` feature did not propagate down to
`bevy_transform`, so the parallel implementation was not activated when
expected.
- The `bevy_log` dependency was pulled in unconditionally via the `std`
feature, when the only use was optional trace-level warnings.

## Solution

- Added an explicit `multi_threaded` feature to `bevy_transform`, backed
by `bevy_tasks/multi_threaded`, matching the pattern used by `bevy_ecs`
and other crates.
- Replaced all `#[cfg(feature = "std")]` / `#[cfg(not(feature =
"std"))]` guards on parallel/serial code paths with
`#[cfg(all(not(target_arch = "wasm32"), feature = "multi_threaded"))]` /
`#[cfg(any(target_arch = "wasm32", not(feature = "multi_threaded")))]` —
the same guard pattern already used in `bevy_ecs`.
- Added `bevy_transform/multi_threaded` to `bevy_internal`'s and
`bevy_render`'s `multi_threaded` feature lists so parallel transforms
are activated end-to-end when building Bevy with `multi_threaded`.
- Removed the `bevy_log` dependency from `bevy_transform`. Its sole
usage was a `warn_once!` inside `propagate_transforms_for`. This is
replaced with a direct `tracing::warn!` wrapped in `bevy_utils::once!`,
gated on a new opt-in `trace` feature (`dep:tracing`). This keeps the
default build lighter.
- Inlined the `trace` feature spans in `mark_dirty_trees` that
previously depended on `bevy_log`'s re-exported `tracing`, now using
`tracing` directly under `#[cfg(feature = "trace")]`.

## Testing

- All existing unit tests in `bevy_transform::systems::test` pass
unchanged — no behavioral changes, only cfg guard corrections.
- No performance regressions observed by
[Benchmark](https://github.com/bevyengine/bevy/pull/23906).

---

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
2026-04-22 05:03:10 +00:00
shunkie c847aafdbb Rename MeshPipelineSet to MeshPipelineSystems (#23823)
# Objective

According to #18900 , rename `MeshPipelineSet` to `MeshPipelineSystems`
for a consistent naming convention.
`MeshPipelineSet` was introduced in this cycle, so no migration guide
required.

## Testing

```
cargo run --example specialized_mesh_pipeline
```
2026-04-19 17:06:23 +00:00
ickshonpe 42aeb763c1 ComputedStackIndex component (#23878)
# Objective

Split off the stack index field from `ComputedNode` into its own
specialized component.
* Makes for a cleaner UI schedule and a clearer division of
responsibilities.
* More fine-grained change detection, might allow for some new
optimisations.

Fixes #23862

## Solution

* Remove the `stack_index` field and its accessor from `ComputedNode`.
* New component `ComputedStackIndex`, newtyping a `u32`.
* Require `ComputedStackIndex` on `ComputedNode`. 
* In `ui_stack_system`, query for and update `ComputedStackIndex`
instead of `ComputedNode`.
* In rendering add queries for `ComputedStackIndex`.
* Removed the ambiguity supression for `ui_stack_system`, as no longer
needed.

Notes
* `ui_stack_system` should probably replace its `With<Node>` query
filters with `With<ComputedStackIndex>`. It uses the ghost hierarchy
navigation params though, which complicates things, so I left them alone
here.
* In the future it might make sense to make the value optional, with
`None` indicating the UI node was removed from the layout via
`Display::None`.

---------

Co-authored-by: François Mockers <francois.mockers@vleue.com>
2026-04-19 17:06:11 +00:00
andriyDev 61127f6d01 Replace all different load variants in AssetServer with a builder. (#23663)
# Objective

- In 0.18, we had 10 different functions that load assets (I'm not even
counting `load_folder`).
- In 0.19, we've even added `load_erased` - but it unfortunately doesn't
support all the features that the other variants support.
- We apparently needed `load_acquire_with_settings_override` which 1)
loads the asset, 2) uses the settings provided, 3) allows reading
unapproved asset paths, and 4) drops a guard once the load completes.
- That's fine if that's necessary. But we needed to create an explicit
variant for that.
- We need fewer load paths!

## Solution

- Create a builder.
- Store all these options dynamically instead of statically handling
each case.
- Have the caller choose a particular "kind" of load when they are
ready: `load`, `load_erased`, `load_untyped`, or `load_untyped_async`.
- I intentionally didn't provide a `load_async` or `load_erased_async`,
since those can be replicated using `load`/`load_erased` +
`AssetServer::wait_for_asset_id` to get the exact same effect.

I am also intentionally leaving `NestedLoader` untouched in this PR, but
a followup will duplicate this API for `NestedLoader`, which should make
it easier to understand.

Unlike the `NestedLoader` API, we aren't doing any type-state craziness,
so the docs are much more clear: users don't need to understand how
type-state stuff works, they just call the handful of methods on the
type. The "cost" here is we now need to be careful about including the
cross product of loads between static asset type, runtime asset type, or
dynamic asset type, crossed with deferred or async. In theory, if we
added more kinds on either side, we would need to expand this cross
product a lot. In practice though, it seems unlikely there will be any
more variants there. (maybe there could be a blocking variant? I don't
think this is a popular opinion though).

A big con here is some somewhat common calls are now more verbose.
Specifically, `asset_server.load_with_settings()` has become
`asset_server.load_builder().with_settings().load()`. I am not really
concerned about this though, since it really isn't that painful.

## Testing

- Tests all pass!

---

## Showcase

Now instead of:

```rust
asset_server.load_acquire_with_settings_override("some_path", |settings: &mut GltfLoaderSettings| { ... }, my_lock_guard);
```

You can instead do:

```rust
asset_server.load_builder()
    .with_guard(my_lock_guard)
    .with_settings(|settings: &mut GltfLoaderSettings| { ... })
    .override_unapproved()
    .load("some_path");
```

We also now cover more variants! For example, you can now load an asset
untyped with a guard, or with override_unapproved, etc.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2026-04-15 18:32:25 +00:00
Talin 574e9356cb Decorative widgets (#23804)
# Objective

Part of #19236 

## Solution

A bunch of new, decorative widgets - see release note.

## Testing

Manual testing

## Showcase

<img width="384" height="207" alt="panes"
src="https://github.com/user-attachments/assets/0b0bb2ee-d520-4280-938e-e08d5c4e49d1"
/>

---------

Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
2026-04-15 15:42:55 +00:00
atlv 082c44ea4c Remove ExtractedView::hdr, add ExtractedView::texture_format, move compositing_space to ExtractedCamera (#23734)
# Objective

- Clean up our texture format handling.
- Fix #23732
- Get us closer to #22563
- It makes no sense for views to talk about being hdr or not. They have
a texture format, that's it. What does HDR shadows even mean lol
- Same for compositing_space

## Solution

- Remove ExtractedView::hdr
- Add ExtractedView::texture_format
- Move ExtractedView::compositing_space to
ExtractedCamera::compositing_space
- Add texture_format to a bunch of specialization keys instead of hdr
bool
- Convert VolumetricFogPipelineKey to not use flags and just use bool
and texture format
- Remove BevyDefault TextureFormat
- Remove ViewTarget TEXTURE_FORMAT_HDR

## Testing

- Pretty extensively test at this point

This has a migration guide.

---------

Co-authored-by: Willow Black <wmcblack@gmail.com>
Co-authored-by: Máté Homolya <mate.homolya@gmail.com>
Co-authored-by: Luo Zhihao <luo_zhihao@outlook.com>
Co-authored-by: IceSentry <IceSentry@users.noreply.github.com>
2026-04-13 20:54:54 +00:00
Rigidity 6356a7d669 Rename Font::try_from_bytes to from_bytes (#23777)
# Objective

Names beginning in `try_` (i.e. `Font::try_from_bytes` in this case)
imply that they are fallible - that is, they return an `Option` or
`Result` if the constructor fails while checking invariants. This method
used to return a `Result`, but no longer does after the recent change to
using `parley`.

## Solution

This PR renames the method to `from_bytes` to convey that it's now
infallible.

## Testing

I switched to my fork locally for my game, and it works with the new
name. There isn't much to test here.

However, this _is_ technically a breaking change to the API (but so is
the existing change on the main branch, so it should be fine).
2026-04-13 00:23:14 +00:00
Doonv 41ef035bde Move WindowPlugin exit systems to Last (#23624)
# Objective

Fix #11874.

## Solution

Old me said that he had problems fixing this, but I just changed the
exit systems to `Last` and I have encountered no issues.

## Testing

CI passes.
I ran several examples including `multiple_windows` and I did the same
changes to 0.18.1 and tested it with my library, I found no errors while
closing the window in both cases.

---------

Co-authored-by: shunkie <shunkie@qq.com>
2026-04-12 20:46:36 +00:00
ickshonpe a3b58f7474 PositionedGlyph migration guide (#23701)
# Objective

The fields removed by #23695 were `pub`, this PR adds a migration guide.
2026-04-12 20:43:08 +00:00
Alice Cecile 9040ceacac Rename FeathersPlugin to FeathersCorePlugin (#23771)
# Objective

`FeathersPlugin` is extremely similar to `FeathersPlugins`. This is
particularly bad because they can both be added via `.add_plugins`.

Fixes #21213.

## Solution

Rename to `FeathersCorePlugin`. It's a perfectly inoffensive name, and
will not be accidentally confused.
2026-04-12 19:20:48 +00:00
Alice Cecile ffa4b0e8d9 Add FocusGained and FocusLost entity events (#23723)
# Objective

When working with more complex widgets, users have repeatedly asked for
a way to reliably detect when an entity gains or loses focus. They have
not, however, filed an issue about this 🎟️

These are called
[`focus`](https://developer.mozilla.org/en-US/docs/Web/API/Element/focus_event)
/
[`focusin`](https://developer.mozilla.org/en-US/docs/Web/API/Element/focusin_event)
+
[`blur`](https://developer.mozilla.org/en-US/docs/Web/API/Element/blur_event)
/
[`focusout`](https://developer.mozilla.org/en-US/docs/Web/API/Element/focusout_event)
on the web. The former element in these pairs does not bubble, while the
latter does.

Because Bevy's observer infrastructure allows you to get the original
target of a bubbled event, we can create only bubbling variations.

@viridia has suggested that
https://github.com/bevyengine/bevy/pull/23707 would benefit from a form
of this feature.

## Rejected designs

The simplest approach would be to simply add a `previously_focused`
field on `InputFocus`, and then emit events based on the difference
using an ordinary system. Unfortunately, this has a serious flaw: events
are lost if this changes state multiple times in the same frame.

We can resolve this problem by completely locking down access, and
requiring commands or events to be used to change the input focus. This
ensures no changes are lost and sends them off semi-immediately, but is
a major breaking change to this API and prevents immediate-mode checks
of "what is the current input focus".

## Solution

We can do better. If we sacrifice "FocusGained and Lost must be emitted
immediately", we can track changes inside of `InputFocus`, before
sending them off in an ordinary system.

This is minimally breaking (you have to use the getters/setters now),
and ensures no gained/lost events are ever missed. Users who completely
overwrite `InputFocus` (e.g. by using `from_entity`) will miss changes,
but frankly, you deserve it if you ignore the nice setters and clear
warnings in the docs.

- Define `FocusGained` and `FocusLost` events. Split to their own file
for cleanliness.
- Lock down access to `InputFocus`, forcing users to always go through
the existing getters and setters.
- Modify `InputFocus` to track changes as they have been made.
- Add a system to drain these once-per-frame in `PostUpdate`, converting
them into `FocusGained` and `FocusLost`.
- This timing helps ensure that any user / library code that changes the
focus has time to run, but rendering code that relies on accurate focus
information to display widgets has the information available.
- I could not find existing systems in `PostUpdate` that this needed a
relative ordering for.
- Create an `InputFocusPlugin` to store this new system, stealing some
of the setup that was previously in `InputDispatchPlugin`. Somewhat
incidentally, this fixes #19057, by selecting option 1.

## Testing

I was *not* very confident that my implementation of this logic was
correct, so I wrote a rather aggressive set of mid-level tests, using
`App`.

They pass, so apparently my first implementation was actually good
enough.
2026-04-10 06:53:00 +00:00
Kevin Reid ec254ded7d Make Skybox’s image optional so that Skybox::default() is valid. (#23691)
# Objective

- Partially addresses #23688.
- Prevents use of `Skybox::default()` from causing errors.

## Solution

`Skybox::default()` is problematic because it contains an `Image` that
is not a valid skybox. ~~This change removes the `Default`
implementation and instead provides a `new()` function which takes the
image as a parameter (and also the brightness, which is practically
required).~~ This change makes the `image` field optional so that the
default `None` renders nothing.

Things we could do instead of this:
* Make `Skybox` not implement `Default`. I am informed this is a bad
idea.
* Create a default cubemap image for `default()` to use.

## Testing

Ran the `skybox` and `irradiance_volumes` examples.
2026-04-10 02:41:17 +00:00
Máté Homolya 437d982e1d Atmosphere as entity migration guide (#23675)
# Objective

- Once PR #23651 is merged we need a migration guide for breaking
changes to Bevy's atmosphere.
- Post the release note changes as a new PR to review grammar/writing
separately

## Solution

- Write a migration guide detailing the breaking changes
- Adhere to a friendly non-technical tone 
- Explain the new way of scaling the atmosphere with `Transform`

## Out of scope
- Explain how to customize the apparent up axis (i.e. horizon's
orientation) -> this should follow intuitively but maybe I should add
this too? or maybe this belongs in a release note instead?
2026-04-06 23:38:14 +00:00
Carter Anderson 535cf401cc Reframe old "scene" terminology as "world serialization" (#23630)
Part 2 of #23619 

In **Bevy 0.19** we are landing a subset of Bevy's Next Generation Scene
system (often known as BSN), which now lives in the `bevy_scene` /
`bevy::scene` crate. However the old `bevy_scene` system still needs to
stick around for a bit longer, as it provides some features that Bevy's
Next Generation Scene system doesn't (yet!):

1. It is not _yet_ possible to write a World _to_ BSN, so the old system
is still necessary for "round trip World serialization".
2. The GLTF scene loader has not yet been ported to BSN, so the old
system is still necessary to spawn GLTF scenes in Bevy.

For this reason, we have renamed the old `bevy_scene` crate to
`bevy_world_serialization`. If you were referencing `bevy_scene::*` or
`bevy::scene::*` types, rename those paths to
`bevy_world_serialization::*` and `bevy::world_serialization::*`
respectively.

Additionally, to avoid confusion / conflicts with the new scene system,
all "scene" terminology / types have been reframed as "world
serialization":

- `Scene` -> `WorldAsset` (as this was always just a World wrapper)
- `SceneRoot` -> `WorldAssetRoot`
- `DynamicScene` -> `DynamicWorld`
    - `DynamicScene::from_scene` -> `DynamicWorld::from_world_asset`
- `DynamicSceneBuilder` -> `DynamicWorldBuilder`
- `DynamicSceneRoot` -> `DynamicWorldRoot`
- `SceneInstanceReady` -> `WorldInstanceReady`
- `SceneLoader` -> `WorldAssetLoader`
- `ScenePlugin` -> `WorldSerializationPlugin`
- `SceneRootTemplate` -> `WorldAssetRootTemplate`
- `SceneSpawner` -> `WorldInstanceSpawner`
- `SceneFilter` -> `WorldFilter`
- `SceneLoaderError` -> `WorldAssetLoaderError`
- `SceneSpawnError` -> `WorldInstanceSpawnError`

Note that I went with `bevy_world_serialization` over
`bevy_ecs_serialization`, as that is what all of the internal features
described themselves as. I think it is both more specific and does a
better job of making itself decoupled from `bevy_ecs` proper.
2026-04-04 00:31:47 +00:00
Luke Yoo 09ef09eaa5 UiWidgetsPlugins and InputDispatchPlugin are now in DefaultPlugins (#23346)
# Objective

-
[Overview](https://hackmd.io/@UrWywBGGTV6bLjORZhuuPw/BJNPlNCu-g#Overview)
- `UiWidgetsPlugins` is part of `DefaultPlugins`
- Prerequisite for [Remove `Interaction` from
`examples/*`](https://github.com/bevyengine/bevy/pull/23285)

## Solution

- `UIWidgetsPlugins` adds `InputDispatchPlugin`.
- `UIWidgetsPlugins` and `InputDispatchPlugin` are removed from
`FeathersPlugins`.
- `UIWidgetsPlugins` slips into `DefaultPlugins`.

## Testing

Following examples are relevant:
- examples/ui/widgets/feathers.rs
- examples/games/game_menu.rs

## Also

[Migration
Guide](https://github.com/micttyoid/bevy/blob/ui-widgets-to-default-2/_release-content/migration-guides/ui_widgets_plugins_and_input_dispatch_plugin_are_now_default.md)
- Also: e7bab9fb83

[TODO after merge](#issuecomment-4057934697)

---------

Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
2026-04-02 18:46:41 +00:00
ickshonpe 33dbf93bf3 Update ComputedNode for scrollbar thumbs in update_scrollbar_thumb (#23612)
# Objective

Update `ComputedNode` for scrollbar thumbs in `update_scrollbar_thumb`
to avoid delays and system ambiguities.

## Solution

* Removed `Node` from scrollbar thumb node entities. 
* Renamed `CoreScrollbarThumb` to `ScrollbarThumb`.
* `ScrollbarThumb` now requires all the UI components and gains `border`
and `border_radius` fields.
* `update_scrollbar_thumb` now updates `ScrollbarThumb` node's
`UiGlobalTransform` and `ComputedNode` in `PostLayout`.


## Testing

```
cargo run --example scrollbars
```

We need a better scrollbars example, added an issue #23622.

---------

Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2026-04-02 16:05:41 +00:00
ickshonpe 8c3facc625 taffy 0.10 update (#23605)
# Objective

https://github.com/DioxusLabs/taffy/releases/tag/v0.10.0

## Solution

* Updated taffy dependency to version `0.10`.
* Added new enum to `ui_node` `InlineDirection`, maps to `Direction` in
taffy (Bevy already has a `Direction` type in `bevy_ecs`).
* `Node` has a new `direction: InlineDirection` field.

---------

Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
2026-04-02 15:48:28 +00:00
Alice Cecile 5e07be7055 Rename default error handler to fallback error handler (#23610)
# Objective

`DefaultErrorHandler` is a confusing name.

While it is the error handler "used by default" if no alterantive is
provided, it should not be your default choice. Local error handling is
usually better than simply calling `?`.

Moreover, it's quite hard to talk about "the default configuration of
the `DefaultErrorHandler`" in the docs, and very weird to discuss
modifying the default error handler.

## Solution

Rename it to `FallbackErorrHandler`.
Update the docs to match.

This is a better name, since it reflects this pattern's "safety net"
usage, without being confusing to discuss.

Add a deprecated type alias and a migration guide to be nice to users.

EDIT: apparently also mention the new Severity logic in the error
handling example.

---------

Co-authored-by: Mira <specificprotagonist@posteo.org>
Co-authored-by: Chris Biscardi <chris@christopherbiscardi.com>
2026-04-01 23:33:51 +00:00
ickshonpe 0505259162 Fix for the text overflow bug seen in the text_debug example. (#23568)
# Objective

Fix the text overflow bug seen  in the `text_debug` example:

<img width="1924" height="1127" alt="Screenshot 2026-03-29 120536"
src="https://github.com/user-attachments/assets/699baf3d-7f0c-4224-8f7d-d55cb05c6eab"
/>

## Solution

Always assumed this was a bug in Taffy, but realised after working out
the intrinsic sizing needed for `EditableText` that the naive
`TextMeasure` implementation from before didn't respect width
constraints and calculated the width for wrapping based on the
unconstrained available space. This resulted in the text layout
overflowing the node by one line.

* Renamed `MeasureArgs` `width` and `height` to `known_width` and
`known_height`.
* `MeasureArgs` now has two new methods, `resolve_width` and
`resolve_height`. They return the resolved values for the style
constraints along the respective axis and a clamped effective size.
* `Measure::measure` no longer has a `style` parameter. Instead it's
included as a `style` field on `MeasureArgs`.
* Measurement for `ImageNode` and `EditableText` also uses the
`resolve_width` and `resolve_height` methods.

## Testing

```
cargo run --example text_debug
```

## Showcase

<img width="1924" height="1127" alt="Screenshot 2026-03-29 120343"
src="https://github.com/user-attachments/assets/47d764e8-d162-4377-9990-962934b2bb91"
/>
2026-03-30 21:12:07 +00:00
Christian Hughes 31a74f2845 Make Ref copyable (#23549)
# Objective

Trying to write a `bevy_immediate` widget with the following signature:

```rust
fn meter<T: Display>(self, name: impl Into<String>, current: Ref<T>, max: Ref<T>) -> Self;
```

Where it would be called like so (pseudocode):

```rust
#[derive(Component)]
struct Health {
    current: f32,
    max: f32
}

fn render(ui: &mut ImmEntity, health: Ref<Health>) {
    ui.meter("Health", health.map(|v| &v.current), health.map(|v| &v.max));
}
```

However, this results in a compiler error as there's currently no way to
split borrows on a `Ref<T>` (there is no `Ref::clone`).

## Solution

- Make `Ref` both `Clone` and `Copy`, easily allowing split borrows.

Note: `Res<T>` is not `Clone` or `Copy` to make cloning the `T` out
easier, but comparatively `Ref<T>` is much less commonly used (users
primarily write `&T` in their query). And even further, I believe the
amount of users who both use `Ref<T>` and who need to clone the `T` out
will be quite small (we don't even have a `Ref::clone` inherent
function, if that proves anything).

Alternatively, we could add `Ref::clone` as an inherent function, but
the UX on that isn't great.

## Testing

The rust compiler keeps us in check here.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2026-03-30 16:30:31 +00:00