Commit Graph

472 Commits

Author SHA1 Message Date
Carter Anderson a3fa0c2c8f Rename Preferences to Settings in the appropriate places (#24613)
# Objective

`bevy_settings` currently conflates "settings" and "preferences" in a
number of places. The name of the framework itself is Bevy Settings, so
anything that drives general "settings" behaviors should use "settings"
terminology. For example, `PreferencesPlugin` should be `SettingsPlugin`
because it handles _all_ `SettingsGroup` types (regardless of their
"scope" such as "preferences.toml").

## Solution

Use "settings" instead of "preferences" in the appropriate places. I've
also removed the custom `ExitAfterSave` commands in the examples as they
are unnecessary.

This should land in 0.19 because we haven't published this API yet and
getting naming right is important.

---------

Co-authored-by: Dave Waggoner <waggoner.dave@gmail.com>
Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
2026-06-17 04:28:56 +00:00
Visse 6f270d4776 Expose pipeline constants to materials (#24502)
# Objective

Allow materials to use pipeline constants ([pipeline-overridable
constants](https://www.w3.org/TR/WGSL/#override-decls)).
They are already available in wgpu, but bevy didn't expose them.

## Solution

Expose constants in `RenderPipelineDescriptor` &
`ComputePipelineDescriptor`, allowing materials to specify them in their
specilize function.

**Note:** I had to remove the `Eq` derive from
`ComputePipelineDescriptor`, `VertexState` and `FragmentState`, due to
the new f64 field. It was already a bit inconsistent with
`RenderPipelineDescriptor` not having it.

## Testing
- Ran `cargo check`
- Created an example & ran it
- Couldn't run `cargo test` due to it taking looots of disk space to
run, but I have a hard time seeing it break something at runtime

## Showcase

See the added example, where pipeline constants are used to change the
`LEVELS` override in WGSL.
<img width="760" height="289" alt="Screenshot from 2026-05-31 09-46-05"
src="https://github.com/user-attachments/assets/6902757c-aea4-4b91-9ff0-e653ce4c3448"
/>
2026-06-09 00:06:01 +00:00
DavidCrossman 7c77ecd576 Fix documentation typos (#24446)
# Objective

Fix typos and other small issues in the documentation. I can drop the
changes to `bevy_reflect`'s and `bevy_anti_alias`'s crate descriptions
if it's a problem.
2026-06-02 00:52:42 +00:00
Rostyslav Toch 98639670f5 Add many_meshlet_materials stress test example (#23792)
# Objective

- Introduce a dedicated example to measure performance overhead when
dealing with a high number of meshlet instances and unique materials.

## Solution

- Added a new example `many_meshlet_materials` that spawns a
configurable grid of meshlet bunnies.

## Testing

- `SystemInfo { os: "Linux (CachyOS Linux rolling)", kernel:
"6.19.10-1-cachyos", cpu: "AMD Ryzen 7 5800H with Radeon Graphics",
core_count: "8", memory: "15.0 GiB" }`
- `AdapterInfo { name: "AMD Radeon Graphics (RADV RENOIR)", vendor:
4098, device: 5688, device_type: IntegratedGpu, device_pci_bus_id:
"0000:03:00.0", driver: "radv", driver_info: "Mesa 26.0.3-arch2.2",
backend: Vulkan, subgroup_min_size: 64, subgroup_max_size: 64,
transient_saves_memory: false }`
- `cargo run --features=meshlet,https --release --example
many_meshlet_materials`

---

## Showcase

Example works perfectly with 5x5 grid.

<img width="1024" height="599" alt="image"
src="https://github.com/user-attachments/assets/948b42b7-e88e-4a91-9fb7-f1c1b4d27e32"
/>

The issue begins when grid count increases to 10x10. Meshes start
flickering.

<img width="1024" height="598" alt="image"
src="https://github.com/user-attachments/assets/055df47f-39dc-41bc-be05-1978ec352e3a"
/>

With 50x50 meshes, the whole screen flickers.

<img width="1024" height="595" alt="image"
src="https://github.com/user-attachments/assets/7d685a2b-7389-43fe-b04e-a5987136f459"
/>

When running with unique materials, performance significantly drops on
my hardware.

<img width="2224" height="1298" alt="image"
src="https://github.com/user-attachments/assets/8d5b4677-7851-4234-9467-992f8db62a9d"
/>

---------

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
Co-authored-by: François Mockers <francois.mockers@vleue.com>
2026-05-22 12:13:26 +00:00
ickshonpe 6dca76afcf FixedNode (#24323)
# Objective

Allow UI elements to be positioned relative to the viewport rather than
their parent element.

Fixes #9564

## Solution

- New UI marker component `FixedNode`. Requires `Node` and
`OverrideClip`.
- `FixedNode` entities are treated as UI roots in layout, even if they
have a parent.
- `FixedNode`s don't inherit their parent's layout, clipping or
transform context.
- During the taffy layout updates children with `FixedNode` are skipped.
- Added a couple of basic helper functions to `UiSurface`, mainly there
to make the tests a little less painful.
- Added a fairly comprehensive range of new tests, including tests with
`GhostNode`s.
- In the Taffy layout (stored in `UiSurface`) there is nothing to
distinguish `FixedNode`s and root nodes, so they are treated identically
during updates.

--

The original suggestion was to implement it as a `PositionType::Fixed`
variant that could used with `Node`, but I think that would be much more
complicated without support from Taffy. Being able to just directly
query for and filter out `FixedNode` entities directly makes the
implementation much simpler and more efficient.

## Testing

Basic example which shows events bubbling up to the parent from the
fixed node:

```
cargo run --example fixed_node
```

There are also a number of new tests in the `layout` module.

```
cargo test -p bevy_ui --lib --features ghost_nodes
```

---------

Co-authored-by: François Mockers <francois.mockers@vleue.com>
2026-05-21 11:08:44 +00:00
Lennard d2481ccf60 Add OpenType font variations (#24088)
# Objective
Bevy currently supports OpenType `FontFeatures`, but it doesn't support
`FontVariations`, although `parley` has support for them.

Font features are mainly on/off values to vary the font (`u32`), while
font variations are a continuous range of values that can be set to vary
the font (`f32`).

I personally need it for setting `FILL` on the material design icon
font.

## Solution
I implemented `FontVariations` as a separate struct from `FontFeatures`
for now and copied it's api.

However, since both are so similar it's worth considering to merge them
into something like a `FontVariables` with a builder that has
`set_feature` and `set_variation` methods.

## Testing
Added a new example demonstrating how to set the font weight using
`FontVariations` instead of `FontWeight`.

(Setting font weight using `FontFeatures` does not work, although the
documentation suggests it should. I'm not sure if this depends on the
variable font used or whether this is an error in the documentation.)

## Showcase

<img width="946" height="541" alt="Screenshot 2026-05-02 225528"
src="https://github.com/user-attachments/assets/9067191b-8517-4fec-9283-45e57180658a"
/>

---------

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2026-05-08 13:29:06 +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
Martin Edlund c3c118c20c Add support for custom picking data (#23245)
# Objective

- Adds the ability for picking backends to add custom hit data
- Fixes #16186 

## Solution

- Adds an `extra` field to the HitData struct which can take any Data
that implements HitDataExtra. This is stored in an Arc which can be
downcast with a helper function in the system that consumes the hit.
- In the original ticket I suggested using a generic, however this
caused extensive code changes and complications down the line with the
HoverMap and OverMap so I decided against it.

## Testing

- I added an example custom_hit_data to test the new feature
- I tested all other picking examples to ensure they still work as
expected
- I tested the examples on Ubuntu
- I additionally tested the custom_hit_data example in wasm 

---

## Showcase

<details>
  <summary>Click to view showcase</summary>

### Creating custom hits:
```rust
let picks: Vec<(Entity, HitData)> = ray_cast
            .cast_ray(ray, &settings)
            .iter()
            .map(|(entity, hit)| {
                let extra = TriangleHitInfo {
                    triangle_vertices: hit.triangle,
                };

                let hit_data = HitData::new_with_extra(
                    ray_id.camera,
                    hit.distance,
                    Some(hit.point),
                    Some(hit.normal),
                    extra,
                );

                (*entity, hit_data)
            })
            .collect();
```

### Reading custom hits:
```rust
   for hits in pointer_hits.read() {
        for (_, hit) in &hits.picks {
            let Some(info) = hit.extra_as::<TriangleHitInfo>() else {
                continue;
            };
            let Some(vertices) = info.triangle_vertices else {
                continue;
            };

            // do something cool with your custom hit data
        }
    }
```

### An example of what you can do with this
<img width="1291" height="730" alt="image"
src="https://github.com/user-attachments/assets/2d0e8aed-7059-470a-a0f6-1453356cfe6a"
/>


</details>
2026-04-23 16:18:18 +00:00
Alice Cecile 61042b10f0 IME support for text input (#23841)
# Objective

IME support during text input is extremely important for non-Latin
languages: notably the CJK family (Chinese, Japanese, Korean). It would
be very nice to support it in our initial release!

Fixes #23795.

## Solution

1. Peek at the `input/text_input` example that @mockersf made and I
forgot about.
2. Steal its strategy and wire up the IME events to Bevy's proper text
input widgets.
3. Delete the now-obsolete example.
4. Add underlines to tentative characters (exposed by parley :D) so then
users can distinguish what they're typing from what they have typed.
5. Rename `editable_text` to the nicer `text_input`.
6. Create a dedicated example for `ime_support`, which uses system
fonts.
7. Add an `error_once!` to fix a footgun I tripped on when using system
fonts...

Per @mockersf's complaints, I've opted not to ship any new fonts in this
PR: the system fonts actually worked great!

## Testing

I've setup IME support on Windows, and added a small font with Japanese
support to the `editable_text` example.

It works quite well! We can even submit the values!

Known issues:

- when entering Japanese characters, the console is spammed with "ICU4X
data error: No segmentation model found for language: ja". I have no
idea where this is coming from: I think a system dependency is causing
this, and it's bubbled up by `parley`? IDK. Doesn't happen with Latin
characters, and it renders fine so...
-~~tab selecting the IME suggestion causes the selected text entry box
to change. I wasn't sure how we want to fix that, so Ieft it for now.~~
EDIT: fixed!

## Showcase

<img width="470" height="233" alt="image"
src="https://github.com/user-attachments/assets/8f8721b3-6746-46d5-8a20-40de634f52e5"
/>

---------

Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
2026-04-21 04:47:51 +00:00
IceSentry 78cc3bc98c Add feathers_counter (#23756)
# Objective

- The feathers example is more a gallery than a simple introduction to
feathers.
- We need a simple example to introduce people to feathers

## Solution

- Add a simple counter that uses feathers

## Testing

I ran the example on my machine

---

## Showcase


https://github.com/user-attachments/assets/4e827e9a-aed9-4c23-918e-05464a5ada67

It doesn't look super great so any styling suggestion is appreciated.

---------

Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
2026-04-13 21:16:26 +00:00
ickshonpe 5eed63e924 Per character filter for TextEdits (#23704)
# Objective

Add an option to reject `TextEdit`s based on a per character filter.

## Solution

* New component: `EditableTextFilter`. Can be used to set a per
character filter for an `EditableText` entity.
* `TextEdit::insert` and `TextEdit::Paste` edits are ignored unless all
their characters pass the filter.

The filter does not apply to characters already within the
`EditableText`'s text buffer

Initially I thought it would be better to implement the filter at the
widget level, then a key press that results in a rejected edit could be
propagated, but the clipboard isn't available to the keyboard observer
function so paste edits would still need to be filtered when the input
buffer is applied.

I made a branch adding a `TextEditRejected` entity event as an
alternative (that would also notify when an edit failed due to the
`max_characters` limit being exceeded), but left it out of this PR to
keep this one focused on just the filtering.

## Testing

New example:  
```
cargo run --example editable_text_filter
```
2026-04-12 20:45:30 +00:00
andriyDev efc6464f9b Create types to store serializable data about the ECS schedule and provide tools for extracting this data. (#22520)
# Objective

- A step towards #10981.
- Allow us to extract data from an app about the schedules.

Here are also some **non-goals** for this PR. These are left as future
work:

- Extract every piece of data in the schedule. I've focused on a rough
set of information that should let us visualization the most important
parts.
- Provide utilities for interpreting the data. This PR is focused on
just extracting the data, interpreting it comes next.
- Any sort of dot graph tools.

## Solution

- Create ser/de compatible structs for representing schedule data.
- Create a function to get schedule data from an initialized `Schedule`.
- Create a plugin to automatically extract the schedule data for every
schedule in the `App`.
- Note this doesn't include other subapps, I'll also leave that to
another PR.
- Make `bevy_ecs` return edges that build passes added.
- Make `bevy_ecs` return the "build metadata" to the caller, and also
trigger as an event.

## Testing

- Added tests!
- Added an example - it outputs a ron file. I assume its all valid.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
2026-04-06 23:06:15 +00:00
Dylan Sechet 128450bdcc Add rectangular area lights (#23288)
# Objective

Adds initial support for rectangle area lights, closing #7662.

Implements Linearly Transformed Cosines ([Heitz et al,
2016](https://eheitzresearch.wordpress.com/415-2/)), with some tricks
from [these
slides](https://advances.realtimerendering.com/s2016/s2016_ltc_rnd.pdf)
and [the reference
implementation](https://github.com/selfshadow/ltc_code).

## Limitations
There's currently no support for:
- Anisotropic materials (there's [a follow-up
paper](https://aakashkt.github.io/ltc_anisotropic.html) that shouldn't
be too hard to implement on top of this, though)
- Shadows
- Textured lights
- Clustering

## Testing

-  Compared results to eevee/cycles, see showcase section.
- Ran the new example with `cargo run --example rect_light --features
free_camera`, and made sure everythign works at grazing angles and from
behind the light.
- Clearcoat and transmission could probably use more testing, I just
made sure nothing looked obviously broken.
 
---

## Showcase


<img width="1919" height="941" alt="Showcase"
src="https://github.com/user-attachments/assets/f506f05c-4869-4387-aeba-d16944497825"
/>
<img width="1919" height="941" alt="Screenshot From 2026-03-11 11-43-42"
src="https://github.com/user-attachments/assets/c4a44903-784f-4c3e-bd44-84c3fe7bff29"
/>


Varying ground plane roughness:


![grid](https://github.com/user-attachments/assets/4426e9df-cde0-450e-b3b7-5e8c2b9fbdcb)
2026-04-06 22:28:53 +00:00
François Mockers f865af110a Automated test for Bevy through BRP (#23647)
# Objective

- Show how a Bevy app can be automated through BRP

## Solution

- Example app_under_test is a basic app with a randomly placed button.
when the button is clicked, the app quit
- Example automated_test click that button through BRP using
`WindowEvent` so that it goes through the whole of Bevy

## Testing

- Run both example and they both exit

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
2026-04-05 16:39:56 +00:00
ickshonpe 28f99e9618 Minimal editable text scrolling implementation (#23646)
# Objective

Add basic support for scrolling text horizontally and vertically to
EditableText.

## Solution

* New component `TextScroll`. Wraps a Vec2 offset that can be used to
set the scroll position.
* Clip overflowing editable text content automatically.
* New system `scroll_editable_text` sets `TextScroll` to keep the cursor
within view inside the `EditableText`'s content box.
* New `allow_newline` flag on `EditableText`. Allows insertion of
newlines with the enter key.
* `editable_text_system` previously ignored `TextLayout::linebreak`. Now
it's possible to change the line break settings.
* Scrolling only happens after a `TextEdit` is applied.

The implementation here is extremely simple but it has some flaws:
* Depending on the width of the node sometimes the cursor can get
clipped.
* `allow_newlines: false` doesn't block pasting in a section of text
with a newline
* No support for scroll margins yet.
* Drag-to-scroll seems to work, but I'm not super confident in it and it
may need some changes.

Went back and forth over whether `ScrollPosition` should be used instead
of a dedicated component, I think it's probably simpler with
`TextScroll` but not certain. Clipping doesn't use `Node`'s overflow API
and is handled automatically during extraction, always targeting the
content box.

## Testing

```
cargo run --example multiline_text_input
```
2026-04-05 10:24:03 +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
ickshonpe 7dcc2244a9 New multiple_text_inputs example. (#23579)
# Objective

Add another text input example

## Solution

Grid layout with three rows of input, immediate updated copy of its
text, and submitted text.
2026-03-31 16:14:14 +00:00
Balazs Erseki 665d1454af Add audio/play_sound_effect example (#23219)
Add `audio/play_sound_effect` example

# Objective

Add an example that demonstrates how to load an audio file and play it
multiple times on a specific event (pressing space).

## Solution

It is similar to the breakout example, but way shorter and focused. This
example loads a sound effect as a resource with the `FromWorld` trait,
and on a keyboard event spawns an `AudioPlayer` with `DESPAWN` mode.

## Testing

- Built on top of 0.18.1, and moved to master
- Tested by building the examples, and pressing the space a few times
(no overlapping audio)
- Tested also by pressing space as fast as I could do for about 1
minute. Lot of components are spawned, played at the same time, but I've
found no issues.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2026-03-29 16:35:34 +00:00
Luo Zhihao d29347b9f0 Remove cmake and dummy.cpp in Android example (#23548)
# Objective

`libc++_shared.so` is no longer needed after #20323

## Solution

Remove unused `dummy.cpp` and cmake in Android examples.

## Testing

Run:
```sh
cargo ndk -P 26 -t arm64-v8a build -o examples/mobile/android_example/app/src/main/jniLibs -p bevy_mobile_example
cd examples/mobile/android_example
./gradlew assembleDebug
adb install -r ./app/build/outputs/apk/debug/app-debug.apk
```
2026-03-28 16:09:25 +00:00
Joe Buehler 0f6d574d43 upstream: jackdaw transform gizmo (#23435)
# Objective

Upstream `jackdaw`'s `TransformGizmo`!

## Solution

Add `TransformGizmoPlugin` to bevy_gizmos as an optional plugin that
draws on a focused entity and lets the user click/drag to manipulate its
transform. Rotate, Translate, and Scale are all individual gizmos -
perfect opportunity for someone to extend and create a combined gizmo in
a follow-up :)

## Testing

- Manually tested with cargo run --example transform_gizmo --features
free_camera:
  - All three modes (translate, rotate, scale) work
  - Focus switch between objects, and gizmo moves across
  - World/local space toggle and editing
- Tested on Linux (X11)

## Showcase

Mark any entity with `TransformGizmoFocus` to get interactive handles:

```rust
app.add_plugins(TransformGizmoPlugin);

commands.spawn((
    Mesh3d(mesh),
    MeshMaterial3d(material),
    TransformGizmoFocus,
));
 

// Switch modes via resource
mode.set(TransformGizmoMode::Rotate);
```

The `transform_gizmo` example shows input cycling and keyboard mode
switching (1/2/3 for translate/rotate/scale, X to toggle world/local
space)

## Video
### Jackdaw


https://github.com/user-attachments/assets/8193b3ed-ae9c-416d-9514-8fb4f42a1f90

### Transform Example



https://github.com/user-attachments/assets/fea22981-4e61-492e-918e-9791ddf5a00d

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2026-03-27 15:48:52 +00:00
Carter Anderson f4d17d9eb2 Next Generation Scenes: Core scene system, bsn! macro, Templates (#23413)
After much [iteration](https://github.com/bevyengine/bevy/pull/20158),
[designing](https://github.com/bevyengine/bevy/discussions/14437) and
[collaborating](https://discord.com/channels/691052431525675048/1264881140007702558),
it is finally time to land a baseline featureset of Bevy's Next
Generation Scene system, often known by its new scene format name ...
BSN (Bevy Scene Notation).

This PR adds the following:
- **The new scene system**: The core in-memory traits, asset types, and
functionality for Bevy's new scene system. Spawn `Scene`s and
`SceneList`s. Inherit from other scenes. Patch component fields. Depend
on assets before loading as scene. Resolve Entity references throughout
your scene.
- **The `bsn!` and `bsn_list!` macro**s: Define Bevy scenes in your code
using a new ergonomic Rust-ey syntax, which plays nicely with Rust
Analyzer and supports autocomplete, go-to definition, semantic
highlighting, and doc hover.
- **`Template` / `GetTemplate`**: construct types (ex: Components) from
a "template context", which includes access to the current entity _and_
access to the `World`. This is a foundational piece of the scene system.

Note that this _does not_ include a loader for the BSN asset format,
which will be added in a future PR. See the "Whats Next?" section for a
roadmap of the future.

Part of #23030 

## Review Etiquette

This is a big PR. _Please use threaded comments everywhere, not top
level comments_. Even if what you have to say is not anchored in code,
find a line to leave your comment on.

## Overview

This is a reasonably comprehensive conceptual overview / feature list.
This uses a "bottom up" approach to illustrate concepts, as they build
on each other. If you just want to see what BSN looks like, scroll down
a bit!
### Templates

`Template` is a simple trait implemented for "template types", which
when passed an entity/world context, can produce an output type such as
a `Component` or `Bundle`:

```rust
pub trait Template {
    type Output;
    fn build_template(&mut self, context: &mut TemplateContext) -> Result<Self::Output>;
}
```

Template is the cornerstone of the new scene system. It allows us to
define types (and hierarchies) that require no `World` context to
define, but can _use_ the `World` to produce the final runtime state.
Templates are notably:

* **Repeatable**: Building a Template does not consume it. This allows
us to reuse "baked" scenes / avoid rebuilding scenes each time we want
to spawn one. If a Template produces a value this often means some form
of cloning is required.
* **Clone-able**: Templates can be duplicated via
`Template::clone_template`, enabling scenes to be duplicated, supporting
copy-on-write behaviors, etc.
* **Serializable**: Templates are intended to be easily serialized and
deserialized, as they are typically composed of raw data.

The poster-child for templates is the asset `Handle<T>`. We now have a
`HandleTemplate<T>`, which wraps an `AssetPath`. This can be used to
load the requested asset and produce a strong `Handle` for it.

```rust
impl<T: Asset> Template for HandleTemplate<T> {
    type Output = Handle<T>;
    fn build_template(&mut self, context: &mut TemplateContext) -> Result<Handle<T>> {
        Ok(context.resource::<AssetServer>().load(&self.path))
    }
}
```

Types that have a "canonical" `Template` can implement the `GetTemplate`
trait, allowing us to correlate to something's `Template` in the type
system.

```rust
impl<T: Asset> GetTemplate for Handle<T> {
    type Template = HandleTemplate<T>;
}
```

This is where things start to get interesting. `GetTemplate` can be
derived for types whose fields also implement `GetTemplate`:

```rust
#[derive(Component, GetTemplate)]
struct Sprite {
  image: Handle<Image>,
}
```

Internally this produces the following:

```rust
#[derive(Template)]
struct SpriteTemplate {
  image: HandleTemplate<Image>,
}

impl GetTemplate for Sprite {
    type Template = SpriteTemplate;
}
```

Another common use case for templates is `Entity`. With templates we can
resolve an identifier of an entity in a scene to the final `Entity` it
points to (for example: an entity path or an "entity reference" ... this
will be described in detail later).

Both `Template` and `GetTemplate` are blanket-implemented for any type
that implements both Clone and Default. This means that _most_ types are
automatically usable as templates. Neat!

```rust
impl<T: Clone + Default> Template for T {
    type Output = T;

    fn build_template(&mut self, context: &mut TemplateContext) -> Result<Self::Output> {
        Ok(self.clone())
    }
}

impl<T: Clone + Default> GetTemplate for T {
    type Template = T;
}
```

It is best to think of `GetTemplate` as an alternative to `Default` for
types that require world/spawn context to instantiate. Note that because
of the blanket impl, you _cannot_ implement `GetTemplate`, `Default`,
and `Clone` together on the same type, as it would result in two
conflicting GetTemplate impls. This is also why `Template` has its own
`Template::clone_template` method (to avoid using the Clone impl, which
would pull in the auto-impl).
### Scenes

Templates on their own already check many of the boxes we need for a
scene system, but they aren't enough on their own. We want to define
scenes as _patches_ of Templates. This allows scenes to inherit from /
write on top of other scenes without overwriting fields set in the
inherited scene. We want to be able to "resolve" scenes to a final group
of templates.

 This is where the `Scene` trait comes in:

```rust
pub trait Scene: Send + Sync + 'static {
    fn resolve(&self, context: &mut ResolveContext, scene: &mut ResolvedScene) -> Result<(), ResolveSceneError>;
    fn register_dependencies(&self, _dependencies: &mut Vec<AssetPath<'static>>);
}
```

The `ResolvedScene` is a collection of "final" `Template` instances
which can be applied to an entity. `Scene::resolve` applies the `Scene`
as a "patch" on top of the final `ResolvedScene`. It stores a flat list
of templates to be applied to the top-level entity _and_ typed lists of
related entities (ex: Children, Observers, etc), which each have their
own ResolvedScene. `Scene`s are free to modify these lists, but in most
cases they should probably just be pushing to the back of them.
`ResolvedScene` can handle both repeated and unique instances of a
template of a given type, depending on the context.

`Scene::register_dependencies` allows the Scene to register whatever
asset dependencies it needs to perform `Scene::resolve`. The scene
system will ensure `Scene::resolve` is not called until all of the
dependencies have loaded.

`Scene` is always _one_ top level / root entity. For "lists of scenes"
(such as a list of related entities), we have the `SceneList` trait,
which can be used in any place where zero to many scenes are expected.
These are separate traits for logical reasons: world.spawn() is a
"single entity" action, scene inheritance only makes sense when both
scenes are single roots, etc.
### Template Patches

The `TemplatePatch` type implements `Scene`, and stores a function that
mutates a template. Functionally, a `TemplatePatch` scene will
initialize a `Default` value of the patched `Template` if it does not
already exist in the `ResolvedScene`, then apply the patch on top of the
current Template in the `ResolvedScene`. Types that implement `Template`
can generate a `TemplatePatch` like this:

```rust
#[derive(Template)]
struct MyTemplate {
    value: usize,
}

MyTemplate::patch_template(|my_template, context| {
    my_template.value = 10;
});
```

Likewise, types that implement `GetTemplate` can generate a patch _for
their template type_ like this:

```rust
#[derive(GetTemplate)]
struct Sprite {
    image: Handle<Image>,
}

Sprite::patch(|sprite_template| {
    // note that this is HandleTemplate<Image>
    sprite.image = "player.png".into();
})
```

We can now start composing scenes by writing functions that return `impl
Scene`!

```rust
fn player() -> impl Scene {
    (
        Sprite::patch(|sprite| {
            sprite.image = "player.png".into();
        ),
        Transform::patch(|transform| {
            transform.translation.y = 4.0;
        }),
    )
}
```

### The `on()` Observer / event handler Scene

`on` is a function that returns a scene that creates an Observer
template:

```rust
fn player() -> impl Scene {
    (
        Sprite::patch(|sprite| {
            sprite.image = "player.png".into();
        ),
        on(|jump: On<Jump>| {
            info!("player jumped!");
        })
    )
}
```

### The BSN Format

`BSN` is a new specification for defining Bevy Scenes. It is designed to
be as Rust-ey as possible, while also eliminating unnecessary syntax and
context. The goal is to make defining arbitrary scenes and UIs as easy,
delightful, and legible as possible.

It is intended to be usable as both an asset format (ex: `level.bsn`
files) _and_ defined in code via a `bsn!` macro. These are notably
_compatible with each other_. You can define a BSN asset file (ex: in a
visual scene editor, such as the upcoming Bevy Editor), then inherit
from that and use it in `bsn!` defined in code.

```rust
:"player.bsn"
Player
Sprite { image: "player.png" }
Health(10)
Transform {
	translation: Vec3 { y: 4.0 }
}
on(|jump: On<Jump>| {
	info!("player jumped!");
})
Children [
	(
		Hat
		Sprite { image: "cute_hat.png" }
		Transform { translation: Vec3 { y: 3.0 } } )
	),
	(:sword Transform { translation: Vec3 { x: 10. } } 
]
```

Note that this PR includes the `bsn!` macro, but it does not include the
BSN asset format. It _does_ include all of the in-memory / in-code
support for the asset format. All that remains is defining a BSN asset
loader, which will be done in a followup.
### The `bsn!` Macro

`bsn!` is an _optional_ ergonomic syntax for defining `Scene`
expressions. It was built in such a way that Rust Analyzer autocomplete,
go-to definition, doc hover, and semantic token syntax highlighting
works as expected pretty much everywhere (but there are _some_ gaps and
idiosyncrasies at the moment, which I believe we can iron out).

It looks like this:

```rust
fn player() -> impl Scene {
    bsn! {
        Player
        Sprite { image: "player.png" }
        Health(10)
        Transform {
            translation: Vec3 { y: 4.0 }
        }
        on(|jump: On<Jump>| {
            info!("player jumped!");
        })
        Children [
            (
                Hat
                Sprite { image: "cute_hat.png" }
                Transform { translation: Vec3 { y: 3.0 } } )
            ),
            (:sword Transform { translation: Vec3 { x: 10. } } 
        ]
    }
}

fn sword() -> impl Scene {
    bsn! {
       Sword
       Sprite { image: "sword.png" } 
    }
}

fn blue_player() -> impl Scene {
    bsn! {
        :player
        Team::Blue
        Children [
            Sprite { image: "blue_shirt.png" } 
        ]
    }
}
```

I'll do a brief overview of each implemented `bsn!` feature now.

### `bsn!`: Patch Syntax

When you see a normal "type expression", that resolves to a
`TemplatePatch` as defined above.

```rust
bsn! {
    Player {
        image: "player.png"
    }
}
```

This resolve to the following:

```rust
<Player as GetTemplatePatch>::patch(|template| {
    template.image = "player.png".into();
})
```

This means you only need to define the fields you actually want to set!

Notice the implicit `.into()`. Wherever possible, `bsn!` provides
implicit `into()` behavior, which allows developers to skip defining
wrapper types, such as the `HandleTemplate<Image>` expected in the
example above.

This also works for nested struct-style types:

```rust
bsn! {
    Transform {
        translation: Vec3 { x: 1.0 }
    }
}
```

Note that you can just define the type name if you don't care about
setting specific field values / just want to add the component:

```rust
bsn! {
    Transform
}
```

To add multiple patches to the entity, just separate them with spaces or
newlines:

```rust
bsn! {
    Player
    Transform
}
```

Enum patching is also supported:

```rust
#[derive(Component, GetTemplate)]
enum Emotion {
    Happy { amount: usize, quality: HappinessQuality },
    Sad(usize),
}

bsn! {
    Emotion::Happy { amount: 10. }
}
```

Notably, when you derive GetTemplate for an enum, you get default
template values for _every_ variant:

```rust
// We can skip fields for this variant because they have default values
bsn! { Emotion::Happy }

// We can also skip fields for this variant
bsn! { Emotion::Sad }
```

This means that unlike the `Default` trait, enums that derive
`GetTemplate` are "fully patchable". If a patched variant matches the
current template variant, it will just write fields on top. If it
corresponds to a different variant, it initializes that variant with
default values and applies the patch on top.

For practical reasons, enums only use this "fully patchable" approach
when in "top-level scene entry patch position". _Nested_ enums (aka
fields on patches) require specifying _every_ value. This is because the
majority of types in the Rust and Bevy ecosystem will not derive
`GetTemplate` and therefore will break if we try to create default
variants values for them. I think this is the right constraint solve in
terms of default behaviors, but we can discuss how to support both
nested scenarios effectively.

Constructors also work (note that constructor args are _not_ patched.
you must specify every argument). A constructor patch will fully
overwrite the current value of the Template.

```rust
bsn! {
    Transform::from_xyz(1., 2., 3.)
}
```

You can also use type-associated constants, which will also overwrite
the current value of the template:

```rust
bsn! {
    Transform::IDENTITY
}
```

If you have a type that does not currently implement
Template/GetTemplate, you have two options:

```rust
bsn! {
    // This will return a Template that produces the returned type.
    // `context` has World access!
	template(|context| {
	    Ok(TextFont {
	        font: context
	            .resource::<AssetServer>()
	            .load("fonts/FiraSans-Bold.ttf").into(),
	        ..default()
	    })
	})
	
	// This will return the value as a Template
	template_value(Foo::Bar)
}
```
### `bsn!` Template patch syntax

Types that are expressed using the syntax we learned above are expected
to implement `GetTemplate`. If you want to patch a `Template` _directly_
by type name (ex: your Template is not paired with a GetTemplate type),
you can do so using `@` syntax:

```rust
struct MyTemplate {
    value: usize,
}

impl Template for MyTemplate {
    /* impl here */
}

bsn! {
    @MyTemplate {
        value: 10.
    }
}
```

In most cases, BSN encourages you to work with the _final_ type names
(ex: you type `Sprite`, not `SpriteTemplate`).

However in cases where you really want to work with the template type
directly (such as custom / manually defined templates), "Template patch
syntax" lets you do that!
### `bsn!`: Inline function syntax

You can call functions that return `Scene` impls inline. The `on()`
function that adds an Observer (described above) is a particularly
common use case

```rust
bsn! {
    Player
    on(|jump: On<Jump>| {
        info!("Player jumped");
    })
}
```

### `bsn!`: Relationship Syntax

`bsn!` provides native support for spawning related entities, in the
format `RelationshipTarget [ SCENE_0, ..., SCENE_X ]`:

```rust
bsn! {
    Node { width: Px(10.) } 
    Children [
        Node { width: Px(4.0) },
        (Node { width: Px(4.0) } BackgroundColor(srgb(1.0, 0.0, 0.0)),
    ]
}
```

Note that related entity scenes are comma separated. Currently they can
either be flat _or_ use `()` to group them:

```rust
bsn! {
    Children [
        // Child 1
        Node BorderRadius::MAX,
        // Child 2
        (Node BorderRadius::MAX),
    ]
}
```

It is generally considered best practice to wrap related entities with
more than one entry in `()` to improve legibility.

### `bsn!`: Expression Syntax

`bsn!` supports expressions in a number of locations using `{}`:

```rust
let x: u32 = 1;
let world = "world";
bsn! {
    // Field position expressions
    Health({ x + 2 })
    Message {
        text: {format!("hello {world}")}
    }
}
```

Expressions in field position have implicit `into()`.

Expressions are also supported in "scene entry" position, enabling
nesting `bsn!` inside `bsn!`:

```rust
let position = bsn! {
    Transform { translation: Vec3 { x: 10. } }
};

bsn! {
    Player
    {position}
}
```

### `bsn!`: Inline variables

You can specify variables inline:

```rust
let black = Color::BLACK;
bsn! {
    BackgroundColor(black)
}
```

This also works in "scene entry" position:

```rust
let position = bsn! {
    Transform { translation: Vec3 { x: 10. } }
};

bsn! {
    Player
    position
}
```

### Inheritance

`bsn!` uses `:` to designate "inheritance". Unlike defining scenes
inline (as mentioned above), this will _pre-resolve_ the inherited
scene, making your current scene cheaper to spawn. This is great when
you inherit from large scene (ex: an asset defined by a visual editor).
Scenes can only inherit from one scene at a time, and it must be defined
first.

You can inherit from scene assets like this:

```rust
fn red_button() -> impl Scene {
    bsn! {
        :"button.bsn"
        BackgroundColor(RED)
    }
}
```

Note that while there is currently no implemented `.bsn` asset format,
you can still test this using `AssetServer::load_with_path`.

You can also inherit from functions that return a `Scene`:

```rust
fn button() -> impl Scene {
    bsn! {
        Button
        Children [
            Text("Button")
        ]
    }
}

fn red_button() -> impl Scene {
    bsn! {
        :button
        BackgroundColor(RED)
    }
}
```

Note that because inheritance is cached / pre-resolved, function
inheritance does not support function parameters. You can still use
parameterized scene functions by defining them directly in the scene
(rather than using inheritance):

```rust
fn button(text: &str) -> impl Scene {
    bsn! {
        Button
        Children [
            Text(text)
        ]
    }
}

fn red_button() -> impl Scene {
    bsn! {
        button("Click Me")
        BackgroundColor(RED)
    }
}
```

Related entities can also inherit:

```rust
bsn! {
    Node
    Children [
        (:button BackgroundColor(RED)),
        (:button BackgroundColor(BLUE)),
    ]
}
```

Inheritance concatenates related entities:

```rust
fn a() -> impl Scene {
    bsn! {
        Children [
            Name("1"),
            Name("2"),
        ]
    }
}

fn b() -> impl Scene {
    /// this results in Children [ Name("1"), Name("2"), Name("3") ]
    bsn! {
        :a
        Children [
            Name("3"),
        ]
    }
}
```

### `bsn_list!` / SceneList

Relationship expression syntax `{}` expects a SceneList. Many things,
such as `Vec<S: Scene>` implement `SceneList` allowing for some cool
patterns:

```rust
fn inventory() -> impl Scene {
    let items = (0..10usize)
        .map(|i| bsn! {Item { size: {i} }})
        .collect::<Vec<_>>();
    bsn! {
        Inventory [
            {items}
        ]
    } 
}
```

The `bsn_list!` macro allows defining a list of BSN entries (using the
same syntax as relationships). This returns a type that implements
`SceneList`, making it useable in relationship expressions!

```rust
fn container() -> impl Scene {
    let children = bsn_list! [
        Name("Child1"),
        Name("Child2"),
        (Name("Child3") FavoriteChild),
    ]
    bsn! {
        Container [
            {children}
        ]
    } 
}
```

This, when combined with inheritance, means you can build abstractions
like this:

```rust
fn list_widget(children: impl SceneList) -> impl Scene {
    bsn! {
        Node {
            width: Val::Px(1.0)
        }
        Children [
            Text("My List:")
            {children}
        ]
    }
}

fn ui() -> impl Scene {
    bsn! {
        Node
        Children [
            list_widget({bsn_list! [
                Node { width: Px(4.) },
                Node { width: Px(5.) },
            ]})
        ]
    }
}
```

### `bsn!`: Name Syntax

You can quickly define `Name` components using `#Name` shorthand.

```rust
bsn! {
    #Root
    Node
    Children [
        (#Child1, Node),
        (#Child2, Node),
    ]
}
```

`#MyName` produces the `Name("MyName")` component output.

Within a given `bsn!` or `bsn_list!` scope, `#Name` can _also_ be used
in _value position_ as an `Entity` Template:

```rust
#[derive(Component, GetTemplate)]
struct UiRoot(Entity);

#[derive(Component, GetTemplate)]
struct CurrentButton(Entity);

bsn! {
	#Root
	CurrentButton(#MyButton)
	Children [
		(
		  #MyButton,
		  UiRoot(#Root)
		)
	]
}
```

These behave a bit like variable names. In the context of inheritance
and embedded scenes, `#Name` is only valid within the current "scene
scope":

```rust
fn button() -> impl Scene {
	bsn! {
		#Button
		Node
		Children [
			ButtonRef(#Button)
		]
	}
}

fn red_button() -> impl Scene {
	bsn! {
		:button
		// #Button is not valid here, but #MyButton
		// will refer to the same final entity as #Button
		#MyButton
		Children [
			AnotherReference(#MyButton)
		]
	}
}
```

In the example above, because `#MyButton` is defined "last" / is the
most "specific" `Name`, the spawned entity will have `Name("MyButton")`

Name references are allowed to conflict across inheritance scopes and
they will not interfere with each other.

`#Name` can also be used in the context of `bsn_list!`, which enables
defining graph structures:

```rust
bsn_list! [
	(#Node1, Sibling(#Node2)),
	(#Node2, Sibling(#Node1)),
]
```
### Name Restructure

The core name component has also been restructured to play nicer with
`bsn!`. The impl on `main` requires `Name::new("MyName")`. By making the
name string field public and internalizing the prehash logic on that
field, and utilizing implicit `.into()`, we can now define names like
this:

```rust
bsn! {
    Name("Root")
    Children [
        Name("Child1"),
        Name("Child2"),
    ]
}
```

### BSN Spawning

You can spawn scenes using `World::spawn_scene` and
`Commands::spawn_scene`:

```rust
world.spawn_scene(bsn! {
    Node
    Children [
        (Node BackgroundColor(RED))
    ]
})?;

commands.spawn_scene(widget());
```

The `spawn_scene` operation happens _immediately_, and therefore assumes
that all of the `Scene`'s dependencies have been loaded (or
alternatively, that there are no dependencies). If the scene has a
dependency that hasn't been loaded yet, `World::spawn_scene` will return
an error (or log an error in the context of `Commands::spawn_scene`).

If your scene has dependencies, you can use `World::queue_spawn_scene`
and `Commands::queue_spawn_scene`. This will spawn the entity as soon as
all of the `Scene`'s dependencies have been loaded.

```rust
// This will spawn the entity once the "player.bsn" asset is loaded
world.queue_spawn_scene(bsn! {
  :"player.bsn"
  Transform { position: Vec3 { x: 10. } }
});
```

There are also `spawn_scene_list` variants for everything above:

```rust
world.spawn_scene_list(bsn_list! [
	button("Ok"),
	button("Cancel"),
])
```

`EntityWorldMut` and `EntityCommands` also have some new functionality:

```rust
entity.queue_spawn_related_scene::<Children>(bsn_list! [
	(:"player.bsn", #Player1),
	(:"player.bsn", #Player2),
]);
```

```rust
entity.apply_scene(bsn! {
	Transform { position: Vec3 { x: 10. } }
})?;
```

For scene assets, you can also just add the `ScenePatchInstance(handle)`
component, just like the old Bevy scene system.
### VariantDefaults derive

`GetTemplate` automatically generates default values for enum Template
variants. But for types that don't use `GetTemplate`, I've also
implemented a `VariantDefaults` derive that also generates these
methods.

## What's Next?

### Must happen before 0.19
- [ ] **Sort out `bevy_scene` vs `bevy_scene2`**: The current plan is to
rename `bevy_scene` to `bevy_ecs_serialization`, and remove "scene"
terminology from it. That then frees up `bevy_scene2` to be renamed to
`bevy_scene`. The current `bevy_scene` will need to exist for awhile in
parallel to BSN, as BSN is not yet ready for "full world serialization"
scenarios.
- [x] ~~**Resolve the Default Handle situation**: Currently, to provide
Template support for `Handle`, it implements `GetTemplate`. This of
course conflicts with `impl Default for Handle`. This is pretty
disruptive to non-BSN users (which is currently everyone). We'll want to
sort out a middleground solution in the short term that ideally allows
us to keep `impl Default for Handle` during the transition.~~
- Resolved this by using a [specialization
trick](https://github.com/bevyengine/bevy/pull/23413#discussion_r2961341173)
- [ ] Nested `bsn!` `Scene` tuples to surpass tuple impl limits


### Ideally before 0.19

We likely won't land all of these. The plan is to (ideally) land this PR
before Bevy 0.19 RC1, then _maybe_ land a couple more of these before

- [ ] **Feathers BSN Port**: Largely already done. Just need to
reconcile with current state of main. This will help BSN land well, so
landing it alongside BSN is a high priority.
- [ ] **ResolvedScene-as-dynamic-bundle**: ResolvedScene should insert
all of the components at once as a single bundle, rather than
one-by-one, which is really bad from an archetype move perspective.
Without this, using `world.spawn_scene(scene)` as a
`world.spawn(bundle)` replacement will result in a pretty significant
performance reduction.
- [ ] **`#Name` references in more places**: The UI eventing scenario
_really_ wants `#Name` to be usable in closures. This would functionally
be expressed as a template that returns a closure that accesses a
specific entity. This unlocks a lot of value for UI devs, so ideally it
lands alongside BSN.
- [ ] **Top-down vs bottom-up spawn order**: Currently BSN follows the
normal bevy top-down spawn order. I think we should heavily consider
spawning bottom-up, in the interest of making scene contents available
to "higher level" components in their lifecycle events (ex: a `Player`
component accessing nested entities like "equipment" when inserted). If
we decide to keep things as they are, we probably want to introduce
additional "scene ready" entity events that trigger "bottom up".
- [ ] **Inline field value expressions**: Support cases such as
`px(10).all()
- [ ] **Add EntityPath to EntityTemplate**: Support resolving entity
paths (ex: `"Root/Child1/GrandChild1"`). This is relatively low hanging
fruit, especially if we switch to bottom-up spawning order.
- [ ] **Function Inheritance Caching**: Currently only scene asset
inheritance is pre-computed / cached. For consistency / predictability /
optimizations, function inheritance (ex `:button`) should also be
cached.
- [ ] **`derive(GetTemplate)` generics ergonomics**: Currently this
requires casting spells: `T: GetTemplate<Template: Default +
Template<Output = T>>`

### Near Future
- [ ] **BSN Asset Format**: Add a `.bsn` parser / AssetLoader that can
produce the current `ScenePatch` assets.
- [ ] **Struct-style inheritance**: It would be nice to be able to do
something like `:Button { prop } ` instead of `:button(prop)`. I'd
really like us to explore this being component-tied (ex: associate a
scene with a Button component).
- [ ] **Descendant Patching**: It should be possible to "reach in" to an
inherited scene and patch one of its descendants / children.
- [ ] **Optimize Related Entity Spawning**: This currently inserts the
relationship component first, then spawns the related scene. This
results in an unnecessary archetype move.
- [ ] Observers as relationships
- [ ] **Scene-owned-entities**: Currently when spawning a `Scene`, every
entity defined in the scene is instantiated. Some scenarios would
benefit from Scene instances _sharing_ some unique entity. For example:
defining assets _inside_ of scenes (this would pair nicely with Assets
as Entities) , sharing Observer entities, etc.
- [ ] The `touch_type::<Nested>()` approach could be replaced with `let
x: &mut Nested` for actual type safety (and probably better
autocomplete).
- [ ] Fix Rust Analyzer autocomplete bug that fails to resolve functions
and enums for `<Transform as GetTemplate>::Template::from_transform()`
- [ ] Fix Rust Analyzer autocomplete bug that also suggests function
names when type struct field names. This _should_ be fixed by using
irrefutable `if let` statements. And it would probably allow us to reuse
macro code across enums / structs (and avoid needing to use PathType
inference in this case, which has gnarly corner cases).
### Longer Term
- [ ] **`bsn!` hot patching via subsecond**: [Proof of concept
here](https://github.com/cart/bevy/pull/36)
- [ ] **Reactivity**: This has been proven out
[here](https://github.com/viridia/bevy_reactor/)
- [ ] **BSN Sets**: See the [old design
doc](https://github.com/bevyengine/bevy/discussions/14437) for the
design space I'm talking about here
* This would also allow expressing "flattened" forms of BSN, which makes
diffs easier to read in some case
- [ ] **World to BSN**: If we can support this, BSN can be used for
things like saving Worlds to disk. This might also be useful for
building scene editors.

---------

Co-authored-by: andriyDev <andriydzikh@gmail.com>
Co-authored-by: Nico Zweifel <34443492+NicoZweifel@users.noreply.github.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: copygirl <copygirl@mcft.net>
2026-03-27 03:18:26 +00:00
Martín Maita a80470f5ec Update Rodio to 0.22 (#20323)
# Objective

- Closes #19672 

## Solution

- Updated both `cpal` and `rodio` to their latest versions.
- Updated code to address `rodio`'s breaking changes.
- Reworked audio related feature flags. NOTE: `symphonia` will only be
the default backend for formats with no alternative fallback.
- Added `audio-all-formats` feature collection to easily enable all the
available audio formats using their default backends.
- Replaced `aarch64-apple-ios-sim` target with
`arm64-apple-ios-simulator`.

## Testing

- Tested audio related examples.
- CI checks passing.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Rob Parrett <robparrett@gmail.com>
2026-03-24 23:31:06 +00:00
IceSentry 88f9fdf738 Upstream bevy_infinite_grid (#23482)
# Objective

- Bevy is now at a point where multiple people are experimenting with
editors and pretty much all of them need an infinite grid
- There are various techniques that can be used to render an infinite
grid without artifacts. This one fades out the lines that are too far
from the camera. The general idea is that the grid is rendered in a
fullscreen pass.
- [bevy_infinite_grid](https://github.com/fslabs/bevy_infinite_grid) is
maintained by foresight spatial labs. It has been used by foresight and
other third party projects in production for many years at this point.
This PR upstreams that crate with full permission from foresight.

## Solution

- Upstream bevy_infinite_grid
- A few minor changes were done to bring it in line with the rest of
bevy
- In the process of upstreaming I noticed a few minor issues that I
fixed like using a fullscreen triangle instead of a quad and using
bevy's View instead of custom one.
- The infinite_grid is currently part of bevy_dev_tools since we don't
have an editor crate but I suspect we'll want to move it to an editor
crate down the line. Although I'm sure projects will want to use this
even if they aren't using the official editor.

## Testing

- I tested the example to confirm it works

---

## Showcase

<img width="1280" height="720" alt="infinite_grid_cSJj0G02fP"
src="https://github.com/user-attachments/assets/cacddc5e-9a54-454b-aefa-b7829c34227a"
/>

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2026-03-24 19:31:17 +00:00
Daniel Skates 2de8711a40 Minimal unstyled Text Input with Parley (#23282)
# Objective

- Minimal unstyled Text Input, using Parley,
https://github.com/bevyengine/bevy/issues/23014

## Solution

- Initial work based off of @alice-i-cecile
[parley-text-input](https://github.com/bevyengine/bevy/compare/main...alice-i-cecile:bevy:parley-text-input)
and @ickshonpe 's
[text-editing](https://github.com/bevyengine/bevy/compare/main...ickshonpe:bevy:text-editing)
and
[parley-input](https://github.com/bevyengine/bevy/compare/main...ickshonpe:bevy:parley-input)
branches
- `EditableText` component wraps a `parley::PlainEditor`
- Edits to the text are made via a queue of `TextEdit` items
- We use the `PlainEditor` for layout, and render from there

Relevant schedules are:
- `PreUpdate`, `bevy_ui_widgets::process_text_inputs`
- `PostUpdate`, `bevy_text::apply_text_edits`
- `PostUpdate`, `bevy_ui::editable_text_system`

And in `render_app`:
- `ExtractSchedule`, `bevy_ui_render::extract_text_editable`
- `ExtractSchedule`, `bevy_ui_render::extract_text_cursor`

## Testing

- `cargo run --example editable_text`

---

## Showcase

![text-input-wip4](https://github.com/user-attachments/assets/8f19c539-c076-4374-b4fc-5df18c07b3e8)

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
2026-03-21 21:22:42 +00:00
atlv 1aea391609 Support Custom SystemExecutors (#23414)
# Objective

- Audio wants a realtime-safe executor with minimal checking. This means
no command application or multithreading etc.

## Solution

- Make it possible to supply our own executor.

## Testing

- Tests are updated
- New custom executor example

Note: reviewing commits individually is probably easier.
2026-03-19 20:23:33 +00:00
gregcsokas 71cfd3ec01 Support letter spacing in bevy_text (#23380)
# Objective

- Implements the `LetterSpacing` feature from issue #8781, the
`LineHeight` is already implemented.

## Solution

Connects Bevy's text pipeline to `parley`'s built-in letter spacing
support,
mirroring the approach used for `LineHeight`.
`Rem` and percentage-based sizing are not yet implemented.

## Testing

- Added a `letter_spacing` example that visually validates the feature.
- Fixed AABB-related tests for `text2d`.
- Reviewers can run: `cargo run --example letter_spacing`
- Works like `LineHeight`, but currently only supports `Px()`.
- Note: letter spacing is currently a required field —
  open to making it optional if that's preferred.

## Showcase

`cargo run --example letter_spacing`


Or here is a video about it:


[Kooha-2026-03-16-10-14-23.webm](https://github.com/user-attachments/assets/3d778bd0-c8bc-43d3-b61b-14ae23c3b906)

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
2026-03-18 01:53:20 +00:00
Damon 00b1ff59e4 Extraction Example (#23223)
An example demonstrating automatic and manual extraction of components
from the Main World to the Render World.

This is a common point of confusion for new users that want to do custom
rendering, and I don't think any of the current examples show how to
manually extract components (or aren't at all focused on it at least).

In the future this should probably be changed to be about extraction
between two arbitrary worlds, instead of being specific to the Render
World. Possibly after / if github.com/bevyengine/bevy/pull/22852 is
merged.

---------

Co-authored-by: Chris Biscardi <chris@christopherbiscardi.com>
2026-03-16 19:38:58 +00:00
Talin 24661940b4 Rename examples/games to examples/showcase (#23375)
# Objective

- Rename the `examples/games` directory to `examples/showcase`. The
"showcase" category is used for examples that are more comprehensive and
full-featured than most, but which are not necessarily games.
2026-03-16 07:03:31 +00:00
Chris Russell 753f3ca1be Add write methods to MessageMutator (#23351)
# Objective

Support systems that both read and write messages of the same type.  

This is possible today with various workarounds: Either using
`ParamSet<(MessageReader<M>, MessageWriter<M>)>` or by manually storing
a `Local<MessageCursor<DebugMessage>>` to keep track of the reading
position. But those are both relatively complex for such a simple use
case.

The `ParamSet` workaround would get even more complex if we did #23339,
since it would be necessary to use a fallible system to handle the case
where the `Messages` resource is missing.

## Solution

Create a type that can both read and write messages. It needs to have a
`MessageCursor` and `ResMut<Messages<M>>`... which is exactly what
`MessageMutator<M>` has!

So, rather than creating a new type, simply add `write`, `write_batch`,
and `write_default` to `MessageMutator`.

Update the documentation to point users to use `MessageMutator` rather
than `ParamSet` or `MessageCursor`.
2026-03-14 05:24:07 +00:00
Tauan Binato 630a5ee362 Remove redundant sampling_primitives example (#23333)
## Objective

Fixes #15823

The `sampling_primitives` and `random_sampling` examples are redundant —
they both demonstrate sampling random points from primitive shapes and
even had identical doc descriptions. Per maintainer consensus,
`sampling_primitives` should be removed.

## Solution

- Removed `examples/math/sampling_primitives.rs`
- Removed the corresponding entry from `Cargo.toml`
- Removed the corresponding entry from `examples/README.md`

## Testing

- Verified `random_sampling` example still exists and is unmodified
- Confirmed no other files reference `sampling_primitives`
2026-03-14 04:58:12 +00:00
Talin 53050f90e2 New bevy_settings crate (#23034)
Yet another attempt at implementing bevy preferences. This version uses
bevy_reflect serialization to convert resources from toml values into
Rust types and vice versa. This is based on the feedback that I got from
the earlier attempt in #22770

To indicate that a resource type should be loaded as preferences, you'll
need to add the `SettingsGroup` annotation:

```rust
#[derive(Resource, SettingsGroup, Reflect, Default)]
#[reflect(Resource, SettingsGroup, Default)]
struct Counter {
    count: i32,
}
```

This will produce a TOML file that looks like this:

```toml
[counter]
count = 3
```

## Theory of Operation

The `PreferencesPlugin` scans the type registry for all resource types
that impl `SettingsGroup` and `Default`. Derive attributes can be used
to write the resource to a different file (or different key in browser
local storage).

`PreferencesPlugin` should be added before other plugins. This ensures
that any other plugins can have access to the settings data during
initialization.

The loader checks to see if the resource already exists; if so, it uses
that resource instance and patches the toml values into it, preserving
any defaults that have been set. If the resource does not exist, it
constructs a new one via `ReflectDefault` before applying the toml
properties.

(There was a suggestion of using `FromWorld` instead of `Default`. This
is worth considering, although there may be issues with calling
`FromWorld` so early in the app initialization lifecycle, before most
resources have been created.)

On `wasm` platforms, this uses browser local storage rather than the
filesystem to store preferences. On platforms which have neither,
preferences are not supported (although it's possible that some
platform-specific settings storage could be implemented).

## Note on terminology

I've tried to consistently use the term "preferences" rather than
"settings" or "config" because those are broader terms. For example, the
`xorg.conf` file, commonly used to configure an XWindows display, is
technically a "settings" file, but it is not "preferences". However, for
end users it's perfectly permissible to use the word "Settings" in menus
and navigation elements since that is the term most commonly used in
software today.

## Open Issues

### Syncing with non-resources

Some important settings are not stored in resources: one of the most
common things that users will want to preserve is the window position
and size, which exist on the window entity. It's not possible, under my
design, to store arbitrary entities as preferences, so in order for the
window properties to be saved they will have to be copied to a resource
before being serialized. We probably don't want to be continually
copying the window size every time the window is dragged or moved, so
we'll need some way to know when serialization is about to happen. I'm
thinking that possibly some global event could be triggered just before
serialization, and the handlers could use this event to make last-minute
patches to resources.

## Saving If Changed

Because saving involves i/o, we want to only save when preferences have
actually changed. This involves two discrete checks:

* Whether a save operation needs to be done at all
* Which files need to be saved

The reason for these two steps is that even checking which files need to
be saved is non-trivial and probably should not be done every frame.

Rather than check the `is_changed()` field of every preference resource
every frame, the code currently relies on the user to issue an explicit
`Command` whenever they change a preferences property. This gets
especially tricky if the settings to be saved aren't actually in a
resource, like the aforementioned window position.

There are two forms of the command: `SavePreferences` and
`SavePreferencesSync`. The former, which uses an i/o task, is the
preferred approach, unless the app is about to exit, in which case the
sync version is preferred.

Once we know that a save will take place, a second pass can be used to
check the timestamp on every resource: if any resource has a tick value
later than the last time the file was either loaded or saved, then we
know that file is out of date.

Also some properties can change at high frequency - for example,
dragging the master volume slider changes the volume every frame. For
this reason, we will generally want to put in a delay / debounce logic
to batch updated together (not present in this PR). However, this delay
means that if the user adjusts the setting and then immediately
terminates the app, the setting won't be recorded. (There is no chance
of the file being corrupted, as it uses standard practices for ensuring
file integrity.)

Unfortunately, on some platforms, depending on how the user chooses to
quit (Command-Q on Mac) there's no opportunity to listen for the
`AppExit` event. For this reason, it's best to use a "belt and
suspenders" approach which listens for both `AppExit` and autosave timer
events.

Fixes #23172
Fixes #13311

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
2026-03-10 20:29:09 +00:00
andriyDev 935936ded5 Add an ImageSaver AssetSaver, and simplify / split the asset saving example (#23105)
# Objective

- Allow users to save images.
- Make a "simple" example of asset saving (as opposed to the existing
complex example).

## Solution

- Pass in the asset path to `AssetSaver`s.
- Make `get_full_extension` return a `&str` instead of an owned
`String`.
- Created a new `ImageSaver` that currently only supports PNG.
- We can extend this in the future if we want more support. It's not
super straightforward since e.g., JPEG doesn't support alpha and wgpu
TextureFormat doesn't have a regular RGB8 format.
- Renamed the old `asset_saving` example to
`asset_saving_with_subassets`.
- Created a new `asset_saving` example which allows drawing an image and
then saving it.

## Testing

- The new example works!
2026-03-10 05:11:21 +00:00
Alice Cecile 8b2dfb5464 Add an example demonstrating callbacks with one-shot systems (#23197)
# Objective

This is a powerful pattern, but figuring out the exact incantation to
call can be quite challenging!

## Solution

Write a little prototype, turn it into a full example!

## Testing

`cargo run --example callbacks`

---------

Co-authored-by: Chris Biscardi <chris@christopherbiscardi.com>
2026-03-03 17:36:33 +00:00
andriyDev 68044242c0 Create an example to show generating assets at runtime. (#23116)
# Objective

- Show how to create assets at runtime.
-
https://discord.com/channels/691052431525675048/691052431974465548/1475244907047424236

## Solution

- Create an example.

## Testing

- The example works!

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2026-02-25 07:47:34 +00:00
Runi-c 1fdf4267ae Add a DelayedCommands helper to support arbitrary delayed commands (#23090)
# Objective

- A generalized mechanism for "doing something later" is desirable for
many games, especially when it comes to gameplay logic and VFX.
- Fixes https://github.com/bevyengine/bevy/issues/15129
- Closes #20155

## Solution

- Build off the work in
https://github.com/bevyengine/bevy/pull/20155#issuecomment-3702483127,
especially @laundmo's comment.
- Add a `DelayedCommands` helper obtainable via `commands.delayed()`
that owns `CommandQueue`s and hands out new `Commands` bound to them.
- When the `DelayedCommands` helper is dropped, push spawn commands onto
the host `Commands` to spawn the queues as `DelayedCommandQueue`
entities.
- The entities are ticked by a new system added by `TimePlugin`. When
the timer fires, the queue is submitted onto that system's `Commands`.

## Testing

- Added a new test in `bevy_time` and it seems to work.
- I'm not very familiar with doing hacky things like using `Drop` like
this and would therefore appreciate careful review and guidance if
changes are requested.

---

## Showcase

```rust
fn my_cool_system(mut commands: Commands) {
    // fairly unobtrusive one-line delayed spawn
    commands.delayed().secs(0.1).spawn(DummyComponent);

    // the DelayedCommands can be stored to reuse more tersely
    let mut delayed = commands.delayed();
    // allocation happens immediately so you can even queue
    // further operations on entities that aren't spawned yet
    let entity = delayed.secs(0.5).spawn_empty().id();
    delayed.secs(0.7).entity(entity).insert(DummyComponent);

    // `delayed.secs` and `delayed.duration` both simply return a
    // `Commands` rebound to the stored `CommandQueue`, so you can additionally
    // just store that and reuse it to queue multiple commands with the same delay
    let mut in_1_sec = delayed.duration(Duration::from_secs_f32(1.0));
    in_1_sec.spawn(DummyComponent);
    in_1_sec.spawn(DummyComponent);
    in_1_sec.spawn(DummyComponent);
}
```

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2026-02-24 23:29:32 +00:00
trepidacious 87c9a5a0ef Support Tile transforms in TilemapChunk (#22889)
# Objective

Fixes #22888 

## Solution

- Add an `orientation` field to `TileData`. This contains a
`TileOrientation` enum representing the tile being rotated and/or
mirrored. This defaults to the current orientation (tile is not rotated
or mirrored). The orientation is packed into the `flags` of
`PackedTileData` as 3 new bits alongside the existing `visible` boolean.
The bits represent mirroring horizontally (left and right swapped),
mirroring vertically (top and bottom swapped), and diagonally (top-right
and bottom-left corners are swapped). Together, the 8 combinations
represent all possible combinations of 90 degree rotations with
mirroring in the X or Y axis.
- Update `tilemap_chunk_material.wgsl` to unpack the bits, and use them
to modify the `local_uv` as needed to apply the transform to the tile.

`TileOrientation` also provides some convenience methods for
construction, and for treating the orientation as a transform that can
be inverted and combined, as well as applying that transform to an
`IVec2`.

There is a new `tilemap_chunk_orientation` example showing all
orientations, combined with tile indices, color, alpha and visibility to
check packing of data.

## Testing

There are some simple tests on the `TileOrientation` itself (e.g.
checking that combining an orientation with its inverse produces the
default orientation, applying each orientation as a transform to a test
`IVec2` to confirm the result is as expected based on manually worked
out expected results, and that inverses will map a point back to its
origin).

Rendering can be tested using the new example, I've tested this on a
Macbook M1 Max.

---

## Showcase

The new `tilemap_chunk_orientation` example uses one tileset entry for
each tile on each row, showing the 8 transforms along the row:

<img width="687" height="707" alt="Screenshot 2026-02-23 at 14 25 29"
src="https://github.com/user-attachments/assets/9cb20236-d180-490c-bd3f-f6e61c30c099"
/>

This also shows different colors and alpha values on each of 8 rows to
check they work alongside transforms, the top row is set to invisible.
The `tileset_index` alternates per row.

This uses a simple two-tile tileset, shown below scaled up by 4:

<img width="32" height="64" alt="arrow"
src="https://github.com/user-attachments/assets/5536beb9-7a3e-4ec0-a667-777ba8ad283a"
/>

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2026-02-24 00:17:21 +00:00
Greeble 0339de9571 Add many_morph_targets stress test (#18536)
## Objective

I wanted to benchmark the morph target changes in #18465. I also wanted
to test morph targets on multiple meshes, which is not covered by
existing examples.

## Solution

Add a stress test for morph targets, similar to `many_cubes` and
`many_foxes`. Spawns a ton of meshes (defaults to 1024) and animates
their morph target weights.


![425571366-b043c16c-6e6a-491e-a0bd-5ece630d7bf8](https://github.com/user-attachments/assets/86ef26a4-ad00-46fa-9e5a-0aa4238023e3)

## Testing

```sh
cargo run --example many_morph_targets

# Test different mesh counts.
cargo run --example many_morph_targets -- --count 42
```

Tested on Win10/Vulkan/Nvidia, Wasm/WebGL/Chrome/Win10/Nvidia.
2026-02-16 22:55:00 +00:00
Kevin Chen e696fa7526 Debug Frustum Culling Usage Example (#22900)
# Objective

- Fixes #22881 . Now that we have Aabb & Frustum Gizmos, let’s provide
an example of their usage!

## Solution

- A new usage example focused on debugging frustum culling. Using a free
camera, you can inspect a scene with another stationary camera that has
its frustum visualized and various shapes that interact with the
frustum.

## Testing

`cargo run --example debug_frustum_culling --features=“free_camera”`


https://github.com/user-attachments/assets/08add970-4e80-4ac1-a81b-32b691f0a803

---------

Co-authored-by: Quinn Mueller <1271721+Smerom@users.noreply.github.com>
2026-02-13 07:05:19 +00:00
ickshonpe 133c8abe19 Stroke font text gizmos (#22732)
# Objective

Lightweight immediate mode stroke fonts text gizmo implementation.

Fixes #16490

## Solution

New `bevy_gizmos` module `text` containing functions `text` and
`text_2d` implemented for `GizmoBuffer`.

The `text` function has parameters:
- `isometry: Into<Isometry3d>`: defines the translation and rotation of
the text.
- `text: &str`: the text to be drawn.
- `size: f32`: the height of the glyphs.
- `anchor: Vec2`: anchor point relative to the center of the text.
- `color: Into<Color>`: the color of the text.

`text_2d` is the same, except the isometry is `Into<Isometry2d>`.

The glyph set is limited to ASCII characters from 33 to 126. 

The text rendering uses the Simplex Hershey font:
https://en.wikipedia.org/wiki/Hershey_fonts
https://paulbourke.net/dataformats/hershey/

The static font data is in the bevy_gizmos::text_font module.
Hershey fonts are public domain and don't require any attribution.

The text geometry isn't retained but since it's so simple, it's still
much faster than the retained Cosmic Text version I wrote initially.
That might not be the case if it's used to display whole pages of text,
but this isn't intended for that.

Glyphs are drawn using linestrips.

### Limitations

* I think this would be better with a monospaced font but it's using a
proportional font atm.

* Only supports left-to-right, left justified text.

* Line height is fixed.

* Can't set the color of individual glyphs.

* Can't change the font.

## Testing

Example displaying text gizmos rotating in 3d
```
cargo run --example 3d_text_gizmos
```

Example displaying all the glyphs from the text gizmos font:
```
cargo run --example text_gizmos_font
```

Larger example with lots of text and an FPS counter:
```
cargo run --example 2d_text_gizmos
```

Example demonstrating anchors:
```
cargo run --example anchored_text_gizmos
```

## Showcase


<img width="1861" height="872" alt="tg-example"
src="https://github.com/user-attachments/assets/d54802cb-23fa-46fc-a20f-3ab004e57f8a"
/>

<img width="792" height="676" alt="anchors"
src="https://github.com/user-attachments/assets/29a8b3b0-516f-4bbc-885e-f8b23db01f88"
/>

<img width="1325" height="405" alt="hello_text_gizmos"
src="https://github.com/user-attachments/assets/b07dc5fb-4be4-4777-b5fd-219c54333328"
/>

<img width="1924" height="1127" alt="all_glyphs"
src="https://github.com/user-attachments/assets/92f7bebd-641c-43a7-9c0a-a56bbb828b5e"
/>

<img width="661" height="738" alt="text-gizmos-3d"
src="https://github.com/user-attachments/assets/91c9caaa-ca13-4a94-9c60-ec326ddeae8a"
/>

<img width="1977" height="1185" alt="2d_gizmos"
src="https://github.com/user-attachments/assets/5f1ae276-795a-4eac-ae2e-3faf7348be2c"
/>

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: François Mockers <francois.mockers@vleue.com>
2026-02-07 19:52:07 +00:00
Patrick Walton 5397e9d201 Implement gradual falloff and blending for light probes. (#22610)
Currently, if a fragment overlaps multiple reflection probes and/or
irradiance volumes, Bevy arbitrarily chooses one to provide diffuse
and/or specular light. This is unsightly. The standard approach is to
accumulate radiance and irradiance as a weighted sum. In most engines,
light probes have an artist-controllable *falloff* range, which causes
the weight of each probe to diminish gradually from the center of the
probe.

This PR implements both falloff and blending for light probes.
Reflection probes and irradiance volumes are blended using a weighted
sum. In the case of reflection probes, if the weights sum to less than
1.0, and an environment map is present on the camera, than the
environment map receives the remaining weight necessary to bring the
total weight up to 1.0. This is useful for reflection probes that
correspond to building interiors, to allow smooth transitions between
the indoor building and an exterior environment map when exiting the
building.

Falloff is specified as a fraction of the *interior* of each light probe
that applies gradual falloff, instead of specifying a distance *outside*
the light probe over which the influence diminishes. (See the
documentation comments in `LightProbe` for more detail.) The reason why
I chose to do it this way is that the voxel contents of an irradiance
volume would be ill-defined within the falloff range otherwise. Clamping
to the edge of the 3D voxel cube inside the falloff region (i.e.
extending the edge voxels out) is likely to be incorrect, and extending
the voxel region to encompass the falloff range plus the interior range
would complicate the calculations in the performance-critical PBR
shader.

A new example, `light_probe_blending`, has been added. This example
shows a reflective sphere that moves between two rooms, each of which
has a reflection probe with a falloff range, so the sphere smoothly
blends between the two. The user can pan and zoom the camera.

<img width="2564" height="1500" alt="Screenshot 2026-01-25 215214"
src="https://github.com/user-attachments/assets/67098769-8082-47c3-ae96-4124732b73f6"
/>
2026-02-04 00:24:30 +00:00
andriyDev 5d9a10c7a6 Implement minimal asset saving (#22622)
# Objective

- A step towards #11216.

## Solution

- Allow users to build `SavedAsset` instances by building up their
labeled assets. This can either take an existing handle + asset ref, or
will create a handle for your asset ref.
- Provide a function to correctly call the `AssetSaver`, and write out
the correct meta file.

### Some things I am leaving to future PRs

- Making it easier to access subassets in an `AssetSaver`.
- Making a nicer API for asset saving (e.g., registering asset savers
and looking up the appropriate saver for type ID + extension).

### Weird implementation details

- I needed to create my own Cow-like type (which I named `Moo`), since I
needed to store just a ref or owned hashmap. I wrote a lengthy comment
explaining why it's needed (TL;DR variance is complicated, Cow doesn't
work). Note: it's possible we could just use CowArc instead, but we
never need to clone the map so this seems like overkill. Also having a
nice place to explain the variance problems is useful here.
- For the builder, I needed to add an extra lifetime to
`add_labeled_asset_with_*<'b: 'a>`, since otherwise, the `CowArc` gets
coerced to `'static` which means the lifetime of the subasset needs to
be `'static`, which practically makes this unusable. By adding a second
lifetime dedicated to the `CowArc`,

## Testing

- Created a new example: this allows you to make a small "scene" of
boxes, and save and load it to your heart's content!
- Added a couple simple tests.
2026-02-04 00:24:23 +00:00
Jenya705 b842bcb923 Contiguous access (#21984)
# Objective

Enables accessing slices from tables directly via Queries.

Fixes: #21861 

## Solution

One new trait:
- `ContiguousQueryData` allows to fetch all values from tables all at
once (an implementation for `&T` returns a slice of components in the
set table, for `&mut T` returns a mutable slice of components in the set
table as well as a struct with methods to set update ticks (to match the
`fetch` implementation))

Methods `contiguous_iter`, `contiguous_iter_mut` and similar in `Query`
and `QueryState` making possible to iterate using these traits.

Macro `QueryData` was updated to support contiguous items when
`contiguous(target)` attribute is added (a target can be `all`,
`mutable` and `immutable`, refer to the `custom_query_param` example)

## Testing

- `sparse_set_contiguous_query` test verifies that you can't use
`next_contiguous` with sparse set components
- `test_contiguous_query_data` test verifies that returned values are
valid
- `base_contiguous` benchmark (file is named
`iter_simple_contiguous.rs`)
- `base_no_detection` benchmark (file is named
`iter_simple_no_detection.rs`)
- `base_no_detection_contiguous` benchmark (file is named
`iter_simple_no_detection_contiguous.rs`)
- `base_contiguous_avx2` benchmark (file is named
`iter_simple_contiguous_avx2.rs`)

---

## Showcase

Examples `contiguous_query`, `custom_query_param`

### Example
```rust
// - self.0 is a World
// - self.1 is a QueryState
// - velocity is a slice of components with Vec3 inside.
// - position is a data structure which implements Deref/DerefMut and IntoIterator methods to access the slice
// as well as mechanism to update update ticks (which it does automatically on dereference), 
// which may be bypassed via `bypass_change_detection` methods.
for (velocity, mut position) in self.1.contiguous_iter_mut(&mut self.0).unwrap() {
    assert!(velocity.len() == position.len());
    for (v, p) in velocity.iter().zip(position.iter_mut()) {
        p.0 += v.0;
    }
}
```

### Benchmarks
Code for `base` benchmark:
```rust
#[derive(Component, Copy, Clone)]
struct Transform(Mat4);

#[derive(Component, Copy, Clone)]
struct Position(Vec3);

#[derive(Component, Copy, Clone)]
struct Rotation(Vec3);

#[derive(Component, Copy, Clone)]
struct Velocity(Vec3);

pub struct Benchmark<'w>(World, QueryState<(&'w Velocity, &'w mut Position)>);

impl<'w> Benchmark<'w> {
    pub fn new() -> Self {
        let mut world = World::new();

        world.spawn_batch(core::iter::repeat_n(
            (
                Transform(Mat4::from_scale(Vec3::ONE)),
                Position(Vec3::X),
                Rotation(Vec3::X),
                Velocity(Vec3::X),
            ),
            10_000,
        ));

        let query = world.query::<(&Velocity, &mut Position)>();
        Self(world, query)
    }

    #[inline(never)]
    pub fn run(&mut self) {
        for (velocity, mut position) in self.1.iter_mut(&mut self.0) {
            position.0 += velocity.0;
        }
    }
}
```
Iterating over 10000 entities from **a single** table and increasing a
3-dimensional vector from component `Position` by a 3-dimensional vector
from component `Velocity`

| Name | Time | Time (AVX2) | Description |

|------------------------------|-----------|-------------|--------------------------------------------------------------------|
| base | 5.5828 µs | 5.5122 µs | Iteration over components |
| base_contiguous | 4.8825 µs | 1.8665 µs | Iteration over contiguous
chunks |
| base_contiguous_avx2 | 2.0740 µs | 1.8665 µs | Iteration over
contiguous chunks with enforced avx2 optimizations |
| base_no_detection | 4.8065 µs | 4.7723 µs | Iteration over components
while bypassing change detection through `bypass_change_detection()`
method |
| base_no_detection_contiguous | 4.3979 µs | 1.5797 µs | Iteration over
components without registering update ticks |

Using contiguous 'iterator' makes the program a little bit faster and it
can be further vectorized to make it even faster
2026-02-03 00:02:26 +00:00
atlv 7b0d0a4e0f Add example for triggering and recovering from rendering errors (#22757)
# Objective

- Test suite/demonstration for render recovery

## Solution

- Add an example that has ways to trigger various rendering errors

## Testing

- run it

Note: im opening this separately so that behavior on bevy main can be
compared to upcoming render recovery pr. It doesn't have to merge first
though.
2026-02-02 23:19:39 +00:00
WaterWhisperer 727a350fc6 Sort the UI examples into sub-dirs (#22727)
# Objective

- Fixes #22644

## Solution

- Create new subdirectories for categorization, and update the paths in
`Cargo.toml` and `README`.

## Testing

- `cargo check --example *`
2026-02-01 18:14:10 +00:00
ickshonpe 71435c2c28 Rename the system_fonts example (#22745)
# Objective

The "system_fonts" example's name in its package meta data is the same
as its filename, when the names of the other examples are capitalized
and use spaces.

## Solution

Rename it.
2026-01-30 22:38:22 +00:00
Damon d1ca184079 Web Example Category Typo (#22680)
Fixed a typo in the category of one web example that was putting it into
its own separate category: https://bevy.org/examples/#shader-advanced
2026-01-24 15:07:50 +00:00
Fodesu e00869bc9b ImageNode resizing example (#22606)
# Objective

#22550 

## Solution
It demonstrates the behavior of `NodeImageMode::Auto` and
`NodeImageMode::Stretch` by resizing a group of images using keyboard
input

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
2026-01-23 05:35:26 +00:00
ickshonpe 839b596010 Fix mistake in example description (#22630)
# Objective

Fix a grammatical error in the `image_node` example's description.
2026-01-21 18:52:04 +00:00
atlv dd230f2f4a Parallax-corrected cubemaps for reflection probes (adopted) (#22582)
# Objective

- Adopts and closes #22288

## Solution

- change the example to make it easier to tell if the reflection is
actually matching
- fix the assets because the reflection doesnt actually match
- throw the assets into the asset repo
https://github.com/bevyengine/bevy_asset_files/pull/7

## Testing

- running the example

---------

Co-authored-by: Patrick Walton <pcwalton@mimiga.net>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2026-01-20 20:18:34 +00:00
Fodesu b55363e544 add basic examples for ImageNode (#22553)
#22547,#22548
2026-01-20 20:01:28 +00:00