# Objective
- `winit::event::WindowEvent::MouseWheel::phase` is not exposed
through`bevy_input::mouse::MouseWheel`.
- I hit this when mapping bevy mouse wheel events to `egui`, which
expects a touch phase parameter.
## Solution
- Add `bevy_input::mouse::MouseWheel::phase`.
- For completeness, also add
`bevy_picking::pointer;:PointerAction::Scroll::phase` and
`bevy_picking::events::Scroll::phase`.
## Testing
- `cargo run --example mouse_input_events` with a touch pad and without.
- Observed the `Started`, `Moved` and `Ended` phases showing up
properly.
---
## Future Work
The gesture types should also have `TouchPhase` exposed on them, but
doing so turns this PR quite a bit larger, so I've left them out.
# Objective
No helper nor example code exists for handling multiple radio button
groups. Currently if a user tries to use existing feathers_gallery code
to create multiple radio groups, radio buttons from all other groups
will become unchecked.
## Solution
- Within queries, only update the radio buttons inside their own group
- Add `radio_self_update()` convenience function to encapsulate this
desired behavior
## Testing
Manually tested inside feathers_gallery example
PR #22041 made us use the center of the mesh AABB as the pivot point for
transparent sorting. This is fine in and of itself, but the way it was
implemented involved adding a matrix multiplication to
`collect_meshes_for_gpu_building` for all meshes, not just transparent
meshes. It also added several fields to `RenderMeshInstance` and related
instances for each mesh, even opaque ones. Since most meshes are opaque,
and `collect_meshes_for_gpu_building` is a performance-critical system,
this doesn't strike me as the right tradeoff.
This PR moves the calculation of the mesh center to
`queue_material_meshes`, to take place only after a mesh has been deemed
to be transparent. Not only does this make
`collect_meshes_for_gpu_building` faster, but it also allows us to
remove the various `center` fields, which stored redundant information.
Note that this comes with two tradeoffs:
1. The transparent sorting no longer takes a custom `Aabb` component on
the mesh into account. I doubt anybody was relying on this behavior.
2. We do have to calculate the AABB for the mesh when importing it to
the render world for the first time.
On `bevy_city --size 90 --no-cpu-culling`, this reduces the time spent
in `collect_meshes_for_gpu_building` after the loading screen from mean
84.85 ms, median 73.4 ms to mean 70.62 ms, median 72.5 ms.
Before this PR:
<img width="2756" height="1800" alt="Screenshot 2026-04-07 173043"
src="https://github.com/user-attachments/assets/3157b58c-b4f1-43db-8157-390e5c9c6ff0"
/>
After this PR:
<img width="2756" height="1800" alt="Screenshot 2026-04-07 172952"
src="https://github.com/user-attachments/assets/fda7100b-7695-4226-99e6-71b4c168f980"
/>
# Objective
Temporary simple / suboptimal solution to #23822
It would be very nice to be able to define assets inline in BSN.
## Solution
- Add a new `HandleTemplate::Value` variant, which contains an
`Arc<Mutex<AssetOrHandle<T>>>`
- This template, when first applied, will lock the mutex, insert the
asset value as a new asset, cache the handle in the
`Arc<Mutex<HandleOrTemplate>` and return the handle. Future calls will
lock the mutex and return the cached handle.
- Add `asset_value(SOME_ASSET)` function to improve ergonomics.
- Port `3d_scene` to illustrate
Doing a lock on every spawn is obviously suboptimal. The long term plan
for "inline assets in BSN" is defined in #23822 and will not use this
locking approach.
# Objective
Improved change detection for `EditableText`.
Fixes#23793
## Solution
* Remove the `text_edited` field from `EditableText` that was used for
manual change detection.
* Use the `PlainEditor`'s `Generation` to track changes.
* New component `EditableTextGeneration`. Newtypes `parley::Generation`.
Stores the generation from the last `TextLayoutInfo` update.
* If `EditableText::editor`'s and `EditableTextGeneration`'s generation
values aren't equal, reupdate `TextLayoutInfo`.
* Added support for `TextLayout::justify`.
* Split up `editable_text_system` into two systems
`update_editable_text_styles` and `update_editable_text_layout`. The
text input's style values need to be updated before layout, so the
measure func returns the correct size for the text layout.
* New `EditableText` `testbed_ui` scene.
* Added two numeric inputs to `multiline_text_input` that allow you to
set the height of the multiline input and its fontsize.
* Update selection rects on all changes, not just when a text input is
focused.
## Testing
```
cargo run --example multiline_text_input
```
The cursor appears to be missing for the numeric inputs in the example
but it isn't. The cursor gets clipped because it's at the end of the
right aligned input value text. If you press left it comes into view.
Cursor and scrolling behaviour needs some adjustments but that's out of
the scope of this PR.
# Objective
Spawning a scene on startup is a common pattern. Lets make it easier to
do so!
## Solution
- Add `SpawnSystem` and `SpawnListSystem` traits that are implemented
for functions that return scenes / scene lists, and return a system that
spawns the scene / handles errors.
### Before
```rust
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.run();
}
fn setup(world: &mut World) -> Result {
world.spawn_scene_list(bsn_list![Camera2d, ui()])?;
Ok(())
}
```
### After
```rust
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, scene.spawn())
.run();
}
fn scene() -> impl SceneList {
bsn_list![Camera2d, ui()]
}
```
This cuts out some boilerplate. It also further encourages people to
define standalone "scene functions" rather than embedding them in code,
which is generally a good pattern.
# 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
```
# 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>
# Objective
Finish the bevy_ecs dynamic story. Currently you can register observers
with dynamic triggers and runners, but there's no way to actually
trigger these observers dynamically.
## Solution
Adds three new unsafe `World` functions:
- `trigger_dynamic()`
- `trigger_dynamic_targets()`
- `trigger_dynamic_targets_components()`
These enable observers to be triggered with untyped events and trigger
data. Their implementations are just wiring up some existing internal
structure. Structurally, they are based on their non-dynamic
counterparts.
Also exposes `EventKey::new()` and `EventKey::component_id()` for
constructing event keys from dynamic `ComponentId`s.
## Testing
Several new tests
## Showcase
See updated example
# Objective
- Fix the case where the UpdateMode::reactive is set to Duration::MAX.
## Solution
- When `StartCause::WaitCancelled::requested_resume` is `None`, always
report this case as not having elapsed the wait time.
## Testing
- Ran the desktop_request_redraw with
`UpdateMode::reactive(Duration::MAX)` and now it updates only when a
redraw happens or a window even happens!
# Objective
- Observe events through BRP
## Solution
- Add a observe + watch method to observe events
- remote observer systems are limited to only the event as a parameter,
processing it will have to happen on the client side
- depends on #23797
## Testing
- CI with new test
---------
Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
# Objective
- Resolve 2 "strict ambiguities" for #23843.
- TL;DR the systems update_text_2d_layout, editable_text_system, and
update_editable_text_content_size are ambiguous, but these ambiguities
are "accidentally" solved by automatically inserted apply_deferred
stages.
## Solution
- Make `editable_text_system` and `update_editable_text_content_size`
being ambiguous with `update_text2d_layout`.
- This is the same as the status quo,
- In practice, we should never really have an entity that is both a
Text2D, and also a UI node. It's not exactly clear what the behavior
should even be in that case.
## Testing
- These remove the 2 ambiguities.
- We're just marking these as ambiguous, so there is nothing to really
test.
Co-authored-by: François Mockers <francois.mockers@vleue.com>
# Objective
- CI fails because of a wrong MSRV issue
## Solution
- ~`cargo metadata` creates a lock file with the current stable version,
which is then used by the MSRV~ turns out `cargo metadata --no-deps`
doesn't lock the lock file unlike `cargo metadata`
- ~clear the stable lock file~
- also update the resolver to v3:
https://doc.rust-lang.org/edition-guide/rust-2024/cargo-resolver.html
## Testing
- CI
# Objective
* Bevy UI's accessibility module doesn't set the transform on
accessiblity nodes, ignoring scaling and rotation.
* UI accessibility nodes should be updated before `bevy_winit` updates
the accesskit adaptors, otherwise there will be a frames delay.
## Solution
Replaced the `calc_bounds` systems with a new system
`sync_bounds_and_transforms`.
Each accesskit `Node` corresponding to an `AccessibleNode` UI entity is
now given object-centered coordinates for its bounding rect (instead of
window coordinates) and a transform.
Accesskit uses local transforms so if an accessible node also has an
accessible parent, its transform has to be recomputed relative to its
parent.
## Testing
I modified the button example so that accesskit integration is enabled
by default and the button is drawn at a 45 degrees angle.
```
cargo run --example button
```
Screen readers should only react when the pointer is directly over the
rotated button if the changes are working.
The example changes should be reverted before merging.
# Objective
- Fixes#23840
- Make `TypeIdMap` iteration order depends only on insertion/removals
## Solution
- Replace the backing `HashMap` by an `IndexMap`
## Testing
- CI
Two separate issues:
1. Because we were re-creating the atomics used for tracking which main
texture is "active", post-process writes could be lost across frames
because the atomic was being reset. This is a bug even without MSAA.
2. We need to force writeback when the user opts into `Load` semantics
on their camera and MSAA is enabled, otherwise we'll throw away the main
target texture incorrectly.
# Objective
- Resolves 2 "strict ambiguities" from #23843.
## Solution
- Make these two widget systems ambiguous with the Stack stage.
- This only contains the ui_stack_system which only updates the
stack_index of the `ComputedNode`, which is unused by these systems. So
we don't care about order here.
## Testing
- Fixes the ambiguities in #23846.
# Objective
In the `feathers_gallery` example, on a `TextEditChange`
`handle_hex_color_change` updates `DemoWidgetStates` which causes
`update_colors` to update the hex input triggering another
`TextEditChange`.
## Solution
Only update `DemoWidgetStates` in `handle_hex_color_change` if the new
color is different.
### In Tilemap usage, TilemapChunk implements FromTemplate, so it can be
used directly. However, TilemapChunkTileData cannot; it must be wrapped
in a template before use.
```rust
bsn! {
TilemapChunk {
chunk_size: chunk_size,
tile_display_size: tile_display_size,
tileset: { tileset.clone() },
alpha_mode: AlphaMode2d::default(),
}
template(|_| TilemapChunkTileData(tile_data.clone()))
}
```
### Similar to the previous FontSize PR
(https://github.com/bevyengine/bevy/pull/23724), it can be used after
modification
```rust
bsn! {
TilemapChunk {
chunk_size: chunk_size,
tile_display_size: tile_display_size,
tileset: { tileset.clone() },
alpha_mode: AlphaMode2d::default(),
}
TilemapChunkTileData({ tile_data.clone() })
}
```
# Objective
Fixes https://github.com/bevyengine/bevy/issues/23814
It isn't clear whether we should be detailing what is now possible with
bevy settings (can use enums and tuple structs) in the release notes so
i've left it as is but happy to collate code examples and the toml they
result in and add this.
# Objective
- Resolves a "strict ambiguity" from #23843.
- TL;DR, adding systems before this schedule with `Commands` could cause
these systems being ambiguous.
- A step for #23846.
## Solution
- Explicitly order these lighting bounds updates after the transform
propagation.
## Testing
- This removes a "strict ambiguity" from #23846.
# Objective
- Removes an entirely unused component in `update_gizmo_meshes`.
- Resolve a "strict ambiguity" for #23846.
## Solution
- Remove the arg! Replace with `With<Camera>`.
## Testing
- Ran the `3d_gizmos` example. It still works!
# Objective
Fix#23731
## Solution
1. Slim down QueuedScenes to the minimum by breaking out "waiting
scenes" into its own resource
2. Store two copies of QueuedScene (one in the system and one in the
resource) and mem::swap them when the system runs
## Testing
Added a test, derived from the repro in #23731
# Objective
- Fix#23313
- On macOS, sending `AppExit` sometimes freezes the app
## Solution
- This was caused by a race condition between the main thread and the
render thread both holding an `Arc` to the window
- Make sure more things drop on the main thread in the correct order
## Testing
- Ran the repro a few times, it used to freezes before, it doesn't after
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
# Objective
Allow negative outline offset values
## Solution
Instead of clamping outline offsets to equal or above zero, clamp them
to equal or above the length of the node's shorter side.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Currently BSN inserts each component one-by-one. This is incredibly
expensive, as it forces an archetype move after every insert.
## Solution
Scene templates now write their outputs to reusable bundle scratch space
(which uses a bump allocator). The final bundle is written after all
components (including inherited components) are written to the bundle.
- Introduce a `BundleWriter`, which enables defining a dynamic bundle
using scratch space in a bump allocator. Currently this only supports
writing individual components to the `BundleWriter`, because supporting
arbitrary bundles is much harder (ex: dynamic bundle effects). This
sadly means that we are temporarily constraining both `bsn! { Node }`
and `bsn! { @SomeTemplate }` "template patches" to _require_ a component
output. Custom scene impls can still push arbitrary bundles, which are
inserted before the final dynamic bundle write. In practice I believe
this will cover the relevant use cases in the short term.
- We now skip duplicate insertions of components when spawning inherited
scenes.
- We now write empty RelationshipTarget collections, pre-allocated to
the correct size to the dynamic bundle, which both avoids another
archetype move and ensures we only allocate the inner relationship
target collection once.
- We now write the Relationship component to the dynamic bundle,
avoiding an archetype move
- I added a new "loaded scene inheritance" test variant, just to make
sure that case still works
- `ErasedTemplate` has been moved to `bevy_scene`, as it is now
"opinionated", more specific to `bevy_scene`, and less safe to use in a
general context
<img width="795" height="274" alt="image"
src="https://github.com/user-attachments/assets/68ea02c7-6b7e-4f7c-9474-603188fe6d0b"
/>
These are benchmarks that produce the same UI scene hierarchy through
different means (the benchmarks have been updated to have a few "matrix
wrapper" components to show the cost of archetype moves):
- `immediate_function_scene`: a test of going through the whole "scene
building" process, then spawning. this is the cost of ad-hoc scenes that
don't reuse work from inherited scenes
- `immediate_loaded_scene`: a test where we instantiate a bunch of
inherited scene instances, where the inherited scene has already been
computed / cached.
- `raw_bundle_no_scene`: just spawning the raw bundle directly
# Objective
Part of #19236
The "disclosure toggle" is a small checkbox-like widget which displays a
chevron that toggles between pointing right and pointing down.
## Testing
Manual testing
# Objective
* Fix toggle behavior
* Add more style tokens and polish appearance
The original intention for the Feathers Checkbox was to toggle the
change immediately on mouse press, but currently only toggles on mouse
release, and lacks styling. Both behaviors are desirable depending on
context, such as being able to cancel an expensive checkmark click that
vastly changes render settings, so this pull request allows both, with
the mouse-press behavior enabled via the `ActivateOnPress` component.
In addition to adding styling, there will no longer a visible outline
for the checkbox in the checked state in the default theme. Having a
border and check symbol made it visually busy, especially at small
sizes.
---
## Showcase
### Before
<img width="161" height="83" alt="Screenshot 2026-04-15 at 7 58 09 PM"
src="https://github.com/user-attachments/assets/9cae7bcf-0b2a-46db-954a-b09332a7b06f"
/>
### After
<img width="161" height="108" alt="Screenshot 2026-04-15 at 8 34 57 PM"
src="https://github.com/user-attachments/assets/72d5083f-20db-45cd-8c1b-1ee711fcedf3"
/>
(Not pictured: new intermediate styling for mouse press)
# Objective
- Fix a typo I found in Error's description
## Solution
- Fixed a typo in documentation
## Testing
- Its just a typo fix, checked if IDE displays correct text
# 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>
# Objective
Horizontal equivalent of the `visible_lines` option.
Allow users to set the width of a text input widget by number of glyphs.
Or for proportional fonts, where the glyph widths are non-uniform, it
would use a multiple of the advance width for "0".
## Solution
* New `visible_width: Option<f32>` field on `EditableText`.
* `TextInputMeasure` now has both a width and height field and both are
`Option<f32>`.
* `update_editable_text_content_size` calculates the width if
`visible_width` is `Some`.
* The width is calculated by multiplying the advance width of "0" by the
`visible_width` (if set) and the current scale factor.
## Testing
I altered the hex input in the `feathers` example to so it's sized to
fit 10 characters (includes space for the cursor).
```
cargo run --example feathers --features="experimental_bevy_feathers"
```
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Implements part of https://github.com/bevyengine/bevy/issues/23302
For background on bevy settings see the initial PR:
https://github.com/bevyengine/bevy/pull/23034
## Solution
As we invoke the serde toml serializer:
Single field tuple structs are serialized as single values:
```rust
#[derive(Resource, SettingsGroup, Reflect, PartialEq, Debug, Default)]
#[reflect(Resource, SettingsGroup, Default)]
struct SingleFieldTupleStruct(u8);
```
Results in:
```toml
[single_field_tuple_struct]
single_field_tuple_struct = 0
```
Multi-field tuple structs are serialized as arrays of values, with
nested structs serialized as inline tables:
```rust
#[derive(Reflect, PartialEq, Debug, Default)]
#[reflect(Default)]
struct NestedStruct {
a: u8,
b: u16,
}
#[derive(Resource, SettingsGroup, Reflect, PartialEq, Debug, Default)]
#[reflect(Resource, SettingsGroup, Default)]
struct MultiFieldTupleStruct(u8, NestedStruct);
```
Results in:
```toml
[multi_field_tuple_struct]
multi_field_tuple_struct = [0, { a = 0, b = 0 }]
```
Non-unit enums retain the "key" field with it defaulting the resources
name, with it being serialized into the group table:
```rust
#[derive(Resource, SettingsGroup, Reflect, PartialEq, Debug)]
#[reflect(Resource, SettingsGroup, Default)]
enum EnumSingleTupleVariant {
A(u8),
}
impl Default for EnumSingleTupleVariant {
fn default() -> Self {
EnumSingleTupleVariant::A(0)
}
}
```
Results in:
```toml
[enum_single_tuple_variant.enum_single_tuple_variant]
A = 0
```
The same multi-field tuple serialization occurs in enums:
```rust
#[derive(Resource, SettingsGroup, Reflect, PartialEq, Debug)]
#[reflect(Resource, SettingsGroup, Default)]
enum EnumMultiNewTypeVariant {
A(SingleFieldTupleStruct, MultiFieldTupleStruct),
}
impl Default for EnumMultiNewTypeVariant {
fn default() -> Self {
EnumMultiNewTypeVariant::A(
SingleFieldTupleStruct(0),
MultiFieldTupleStruct(0, NestedStruct { a: 0, b: 0 }),
)
}
}
```
Results in:
```toml
[enum_multi_new_type_variant.enum_multi_new_type_variant]
A = [0, [0, { a = 0, b = 0 }]]
```
Enums variants with fields are serialised with field entries:
```rust
#[derive(Resource, SettingsGroup, Reflect, PartialEq, Debug)]
#[reflect(Resource, SettingsGroup, Default)]
enum EnumStructVariant {
A { x: u8, y: u16 },
}
impl Default for EnumStructVariant {
fn default() -> Self {
EnumStructVariant::A { x: 0, y: 0 }
}
}
```
Results in:
```toml
[enum_struct_variant.enum_struct_variant.A]
x = 0
y = 0
```
## Notes
- I'm not 100% sold on the `[group_name.key_name]` for non-unit like
enums, its easy enough to not include the key for these types but i'll
keep in for the sake of discussion.
- Still not supporting Unions.
https://github.com/bevyengine/bevy/issues/23302 did not mention them but
I can add support for these in this PR or we can just not support them
at all. Open to discussion.
## Testing
- I've added to the above examples to the bevy settings test suite.
- I've ran the `persisting_preferences` example and cross referenced the
toml output in the file.
Fix self intersection artifacts by offsetting the ray origin along the
geometric normal (or shading normal when geo normal not available, e.g.
from gbuffer).
Fixes flickering in Solari's many\_lights test scene.
# Objective
Replace `HashMap<Entity, T>` and `HashSet<Entity>` with `EntityHashMap`
and `EntityHashSet` for better performance.
## Solution
Replace them.
## Testing
CI
# Objective
- Taking screenshots is cool
- Now let's do it through reflection!
## Solution
- Reflect event for ScreenshotCaptured, register Screenshot and
ScreenshotCaptured
- Also set the usage of the image of a screenshot to the main world. it
doesn't change anything but it's less wrong
## Testing
- CI
# Objective
- Some types wrap an image and can be useful to serialise
## Solution
- Implement serialize on Image through SerializedImage
## Testing
- CI
# Objective
As discussed in [this discord
thread](https://discord.com/channels/691052431525675048/1492688648360165406),
using the `Children` relation to append caption elements to feathers
widgets is dodgy.
## Solution
Make `caption` an explicit parameter for button, radio, and checkbox
widgets.
Also fixed some erroneous docs.
## Testing
Manual testing of feathers and bevy_city examples.
Note that there's no migration guide because this only affects the bsn
functions, which are new.