Commit Graph

104 Commits

Author SHA1 Message Date
ickshonpe 8ce450bd98 Another text measurement fix (#24669)
# Objective

Text is wrapped to fit inside the node's content box but the node is
sized as though the text isn't wrapped.

Fixes #24664

## Solution

Subtract the total of the horizontal padding and border insets.

## Testing

Added the replication from #24664 to `testbed_ui`'s `TextWrap` scene:
```
cargo run --example testbed_ui -- textwrap
```

<img width="500" alt="image"
src="https://github.com/user-attachments/assets/e37884d1-7ae6-4aab-b16f-c5af004f5556"
/>

---

The other examples, particularly `text_debug`, shouldn't demonstrate any
changes.

---------

Co-authored-by: Dimitrios Loukadakis <dloukadakis@users.noreply.github.com>
2026-06-21 07:30:04 +00:00
ickshonpe 457b91808a More consistant Font asset resolution and change detection (#24362)
# Objective

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

Fixes #24356

## Solution

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

## Testing

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

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

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

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

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2026-06-04 04:55:04 +00:00
ickshonpe 50242076bf ImageNode measure func fixes and allow drawing inside border and padding (#24154)
# Objective

Allowing drawing with `ImageNode` inside the border and padding boxes of
a UI node.
Fix a lot of image measurement and aspect ratio issues.

Fixes #24150

## Solution

Renamed `OverflowClipMarginBox` to `VisualBox`. 
Added a `visual_box: VisualBox` field to `ImageNode`.
Use the size of the selected node region in image rendering.
Fixed the bugs with the `ImageNode` measure func.

## Testing

Added many more cases to `testbed_ui`'s `image` and `slice` scenes:

```
cargo run --example testbed_ui -- --scene image
cargo run --example testbed_ui -- --scene slice
```

## Showcase

<img width="902" height="530" alt="box"
src="https://github.com/user-attachments/assets/74f873d4-f00e-47c3-ad3a-3640a39466e4"
/>
<img width="962" height="563" alt="borderbox"
src="https://github.com/user-attachments/assets/3b27c8e1-3b27-4a82-b136-95fed19c28ce"
/>
<img width="766" height="541" alt="content"
src="https://github.com/user-attachments/assets/a4543995-a835-45e1-8ffb-5d671fc7ec05"
/>
2026-05-06 15:39:27 +00:00
ickshonpe b00ff93c87 Remove new_with_ prefix from the TextLayout constuctor functions (#24049)
# Objective

Remove the `new_with_` prefixes from the `TextLayout` constuctor
functions. Generally, the "new" part is redundant and "with" is used by
fluent APIs.

## Solution

Just delete the prefixes, shorten the names (all on `TextLayout`).
* `new_with_justify` -> `justify`
* `new_with_linebreak` -> `linebreak`
* `new_with_no_wrap` -> `no_wrap`
2026-05-01 21:08:18 +00:00
Kevin Chen 0e49f63973 Add a rectangular light to the 3d testbed Light scene (#24025)
# Objective

- Regression test for broken Rect Lights

## Solution

- Add a rectangular light to testbed/3d

## Testing

- `cargo run --example testbed_3d` - I can see the new light (well,
after #24024 is merged hehe)

Before (w/o rect light)
<img width="1271" height="747" alt="Screenshot 2026-04-28 at 11 28
16 PM"
src="https://github.com/user-attachments/assets/aa6b6258-e80d-4a98-861c-bcad6e8db541"
/>

After (w/ rect light - it’s behind the cube)
<img width="1271" height="750" alt="Screenshot 2026-04-28 at 11 25
33 PM"
src="https://github.com/user-attachments/assets/877013f0-843a-43f2-9dbd-96f2fa37d8e2"
/>
2026-04-29 03:58:16 +00:00
ickshonpe 8b8a432ab4 EditableText change detection using parley::Generation (#23785)
# 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.
2026-04-19 18:38:47 +00:00
andriyDev 61127f6d01 Replace all different load variants in AssetServer with a builder. (#23663)
# Objective

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

## Solution

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

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

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

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

## Testing

- Tests all pass!

---

## Showcase

Now instead of:

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

You can instead do:

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

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

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2026-04-15 18:32:25 +00:00
Kevin Reid ec254ded7d Make Skybox’s image optional so that Skybox::default() is valid. (#23691)
# Objective

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

## Solution

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

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

## Testing

Ran the `skybox` and `irradiance_volumes` examples.
2026-04-10 02:41:17 +00:00
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
Alice Cecile 36a97620df Add white furnace analog for 2D color consistency (#23589)
# Objective

Create a regression test for
https://github.com/bevyengine/bevy/issues/23577.

## Solution

Copy the white furnace test idea by spawning a bunch of 2D things with
exactly the same color.

Split out from #23584.

## Testing

`cargo run -example testbed_2d`. Press space to get to the example
that's all grey.

Locally, this is all one uniform grey for me: I could not reproduce
#23577.

Still, this is a useful property to test for!
2026-03-31 22:52:46 +00:00
IceSentry 2589ed242f Add render_layers scene to testbed_3d (#23559)
# Objective

- RenderLayers are easy to break and so is multiple viewport support

## Solution

- Add a new scene to testbed_3d that shows multiple cameras at the same
time all with different combinations of render layers

## Testing

- I ran the example locally and toggled between all the scenes

---

## Showcase

<img width="1282" height="752" alt="testbed_3d_KmHPJ8pweU"
src="https://github.com/user-attachments/assets/dad376f3-fd72-424d-b68d-7048843da179"
/>

As you can see, this already highlights a bug with shadows not
respecting render layers
2026-03-29 16:24:00 +00:00
ickshonpe f62d53dbca Bordered and padded content (#23510)
# Objective

Allow borders and padding on text and images.

Fixes #17300, #14498, #14789, #11557, #6879

## Solution

Remove filter for border values on content sized nodes.
Apply content offsets to content in rendering and picking.

## Testing

```
cargo run --example testbed_ui -- boxedcontent
```

```
cargo run --example image_node
```

```
cargo run --example editable_text
```

```
cargo run --example text_background_colors
```

## Showcase

<img width="1924" height="1127" alt="Screenshot 2026-03-25 113700"
src="https://github.com/user-attachments/assets/68be286b-ca0e-46c7-9295-973df77412e9"
/>

<img width="223" height="223" alt="birdd"
src="https://github.com/user-attachments/assets/e9f6e393-7ee9-498b-85d0-318abd702448"
/>
2026-03-25 17:13:34 +00:00
François Mockers 5e6493b82d move white furnace to the 3d testbed (#23207)
# Objective

- https://github.com/bevyengine/bevy/pull/22584 added a white furnace
test, but it was not setup as a testbed
- Fixes #23202 

## Solution

- Add it to the 3d testbed
2026-03-04 03:51:20 +00:00
Dylan Sechet 5b953998ce Disable global ambient light in white furnace test (#23189)
# Objective
The recently added white furnace test doesn't disable global ambient
lighting, which makes the results appear brighter than they should be.

## Solution
Disable global ambient lighting in the white furnace test.

## Testing

- Tested by running `cargo run --example testbed_white_furnace`

The PBR renderer still loses energy for partially metallic materials,
but it appears to work fine for pure dielectrics or metals when using a
solid color light.

---

## Showcase

<img width="1280" height="720" alt="color_based"
src="https://github.com/user-attachments/assets/3491336e-5244-4b57-8f1a-6879edc8b458"
/>
<img width="1280" height="720" alt="image_based"
src="https://github.com/user-attachments/assets/bf59f8f2-2290-490d-beed-c64be44c2d22"
/>
2026-03-02 20:41:25 +00:00
ickshonpe df5cdd0faa Despawn atlas sprites on scene exit in testbed_2d (#23133)
# Objective

Some cleanup is missing from the 2d testbed's `TextureAtlasBuilder`
scene.

## Solution

Add `DespawnOnExit(super::Scene::TextureAtlasBuilder)` to the atlas
sprites.
2026-03-02 19:00:13 +00:00
ickshonpe 1aedbf36d1 Fix the gizmo colors in testbed_2d's texture_atlas_builder scene (#23146)
# Objective

Fix the gizmo colours in testbed_2d instead of basing them on entity
ids.

## Solution

```rust
ShowAabbGizmo {
    color: Some(Color::WHITE),
}
```
2026-03-01 20:14:06 +00:00
Máté Homolya a17dfe4611 Add white furnace test for testing PBR (#22584)
# Objective

- Add a new testbed example demonstrating a white furnace test for PBR
materials
- Provide a tool for verifying that PBR materials correctly conserve
energy under uniform white lighting

## Solution

- Created a new testbed example `examples/testbed/white_furnace.rs`
- Programmatically generate a pure white cubemap using `Rgba16Float`
format with hardcoded f16 bytes
- Use `GeneratedEnvironmentMapLight` to provide the white environment
map for IBL
- Use `Skybox` component to display the white environment as the
background
- Displays a grid of spheres - same as the PBR example
- Enabled HDR rendering, intentionally disabled tonemapping with
`Tonemapping::None` to represent the raw lighting values in the final
output framebuffer
- Added the example to `Cargo.toml`

## Testing

- Tested by running `cargo run --example testbed_white_furnace`
- Confirmed that the white cubemap is correctly generated and applied to
both the skybox and environment lighting

However the test reveals that Bevy's PBR renderer is not energy
conserving under all conditions.

---

## Showcase

<img width="1280" height="751" alt="Screenshot 2026-01-18 at 10 45
17 AM"
src="https://github.com/user-attachments/assets/877ddf69-1c9c-48aa-978e-d7b4884a420e"
/>

this is even more apparent when exporting from the shader debugger
before the display transform is applied.
<img width="2560" height="1440" alt="pre-tonemap"
src="https://github.com/user-attachments/assets/20a2db7f-856e-4648-9d1c-f7e5288ad8dd"
/>

## Open Items

- Add the furnace test to CI /automated test suite to catch regressions
as suggested by Alice
2026-03-01 19:32:11 +00:00
Kaio Matos 4732c21077 The testbed_ui text scene should use a column layout (#23077)
# Objective

Remove unnecessary usage of absolute positioning for each text element
Fixes https://github.com/bevyengine/bevy/issues/22976

## Solution

Uses display grid with two columns to display the `testbed_ui` text.
Beyond that I removed `DespawnOnExit(super::Scene::Text)` from each text
element and added that only to the parent component.

## Testing

Run and hit space once:
```sh
cargo run --example testbed_ui
```

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2026-02-24 01:19:25 +00:00
ickshonpe b03922d484 testbed_2d texture atlas builder scene (#23074)
# Objective

Add a scene displaying the output from `TextureAtlasBuilder`.

## Solution

Add a scene showing the atlases textures and padding and how it affects
the sub images when they are drawn.

## Testing

```
cargo run --example testbed_2d -- textureatlasbuilder
```
2026-02-24 01:15:57 +00:00
ickshonpe c43c8f4c32 Inverted UI node background color (#23043)
# Objective

Fixes #22797

## Solution

New `OuterColor` marker component. Sets a fill color for the area
outside the border created when a border radius is set.

The Implementation is very simple. The shader now has an `INVERT` flag,
if enabled the direction of the rounded corners SDF is flipped.

#

I'm not sure about the `OuterColor` name, but can't think of anything
more descriptive that isn't also annoyingly long.

## Testing

New `testbed_ui` scene:
```
cargo run --example testbed_ui -- outercolor
```

## Showcase

<img width="1924" height="1127" alt="inverted"
src="https://github.com/user-attachments/assets/095f49d6-844a-4b0c-af2b-86b50d40952a"
/>

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2026-02-24 00:27:20 +00:00
Chintan Bhatt 7c153070c0 Adds text gizmos to testbeds (#23064)
# Objective

- Fixed both #23058 and #23059 

## Solution

- Adds text gizmos to the 2D and 3D testbed examples

## Testing

Tested on Windows 11/Nvidia/Vulkan

---

## Showcase

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

### testbed_2d

<img width="1282" height="752" alt="image"
src="https://github.com/user-attachments/assets/ce20cf8f-c6f0-49be-8290-9f912c144f65"
/>


### testbed_3d

<img width="1282" height="752" alt="image"
src="https://github.com/user-attachments/assets/2de280bd-bf2f-4335-a7ba-c25fc9a53d25"
/>


</details>
2026-02-20 05:46:01 +00:00
ickshonpe 92a1255357 Add font hinting example to testbed_ui's text scene (#22970)
# Objective

Add font hinting to the UI testbed text scene.

## Solution

Draw all the cases again without hinting:

<img width="1924" height="1127" alt="Screenshot 2026-02-15 235523"
src="https://github.com/user-attachments/assets/bbd581b4-1249-4f23-939a-0d59e8cccf75"
/>
2026-02-17 00:43:31 +00:00
Trashtalk217 59e9ee3a1a Store Resources as components on singleton entities (#20934)
This is part of #19731.

# Resources as Components

## Motivation

More things should be entities. This simplifies the API, the lower-level
implementation and the tools we have for entities and components can be
used for other things in the engine. In particular, for resources, it is
really handy to have observers, which we currently don't have. See
#20821 under 1A, for a more specific use.

## Current Work

This removes the `resources` field from the world storage and instead
store the resources on singleton entities. For easy lookup, we add a
`HashMap<ComponentId, Entity>` to `World`, in order to quickly find the
singleton entity where the resource is stored.

Because we store resources on entities, we derive `Component` alongside
`Resource`, this means that

```rust
#[derive(Resource)]
struct Foo;
```
turns into
```rust
#[derive(Resource, Component)]
struct Foo;
```

This was also done for reflections, meaning that

```rust
#[derive(Resource, Reflect)]
#[refect(Resource)]
struct Bar;
```
becomes
```rust
#[derive(Resource, Component, Reflect)]
#[refect(Resource, Component)]
struct Bar;
```

In order to distinguish resource entities, they are tagged with the
`IsResource` component. Additionally, to ensure that they aren't queried
by accident, they are also tagged as being internal entities, which
means that they don't show up in queries by default.

## Drawbacks

- Currently you can't have a struct that is both a `Resource` and a
`Component`, because `Resource` expands to also implement `Component`,
this means that this throws a compiler error as it's implemented twice.
- Because every reflected Resource must also implement
`ReflectComponent` you need to import
`bevy_ecs::reflect::ReflectComponent` every time you use
`#[reflect(Resource)]`. This is kind of unintuitive.

## Future Work

- Simplify `Access` in the ECS, to only deal with components (and not
components *and* resources).
- Newtype `Res<Resource>` to `Single<Ref<Resource>>` (or something
similair).
- Eliminate `ReflectResource`.
- Take stabs at simplifying the public facing API.

---------

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Dimitrios Loukadakis <dloukadakis@users.noreply.github.com>
2026-02-10 18:53:12 +00:00
Kevin Chen ff57138b44 Adds tests for new UiDebugOverlay features into testbed_ui (#22673)
# Objective

- Add some recently expanded UI Debug functionality to the testbed
#21931

## Solution

To `testbed/ui.rs`, Adds a second row of entities demonstrating:

1. border, padding, content box outlines with a rounded border radius
2. vertical scrollbar outline
3. horizontal scrollbar outline
4. bidirectional scrollbar outline

The scrollbars were taken from `scroll.rs` and I tried to strip them
down to the barest code that shows them as outlines (so scrolling
doesn’t work with them)

## Testing

`cargo run --example testbed_ui --features="bevy_ui_debug” --
debugoutlines` does the trick

## Showcase

If this screenshot / these new test cases expose(s) any bugs that are
not intended behavior (i.e. why is the bottom left padding box’s corner
also rounded when only the bottom right border radius was specified? Or
why do the bidirectional scrollbars overlap the text?), please make an
issue / let me know so that I can make an issue

<details>
  <summary>Screenshot</summary>

<img width="1282" height="747" alt="Screenshot 2026-01-23 at 6 50 18 PM"
src="https://github.com/user-attachments/assets/a52fcec8-834c-46e9-b7a0-61c3e30cf730"
/>

</details>
2026-02-02 23:04:48 +00:00
ickshonpe 6ca4769128 Minimal responsive FontSize support (#22614)
# Objective

Add responsive font sizes supporting rem and viewport units to
`bevy_text` with minimal changes to the APIs and systems.

## Solution

Introduce a new `FontSize` enum:

```rust
pub enum FontSize {
    /// Font Size in logical pixels.
    Px(f32),
    /// Font size as a percentage of the viewport width.
    Vw(f32),
    /// Font size as a percentage of the viewport height.
    Vh(f32),
    /// Font size as a percentage of the smaller of the viewport width and height.
    VMin(f32),
    /// Font size as a percentage of the larger of the viewport width and height.
    VMax(f32),
    /// Font Size relative to the value of the `RemSize` resource.
    Rem(f32),
}
```

This replaces the `f32` value of `TextFont`'s `font_size` field.

The viewport variants work the same way as their respective `Val`
counterparts.

`Rem` values are multiplied by the value of the `RemSize` resource
(which newtypes an `f32`).

`FontSize` provides an `eval` method that takes a logical viewport size
and rem base size and returns an `f32` logical font size. The resolved
logical font size is then written into the `Attributes` passed to Cosmic
Text by `TextPipeline::update_buffer`.

Any text implementation using `bevy_text` must now provide viewport and
rem base values when calling `TextPipeline::update_buffer` or
`create_measure`.

`Text2d` uses the size of the primary window to resolve viewport values
(or `Vec2::splat(1000)` if no primary window is found). This is a
deliberate compromise, a single `Text2d` can be rendered to multiple
viewports using `RenderLayers`, so it's difficult to find a rule for
which viewport size should be chosen.

### Change detection 

`ComputedTextBlock` has two new fields: `uses_viewport_sizes` and
`uses_rem_sizes`, which are set to true in `TextPipeline::update_buffer`
iff any text section in the block uses viewport or rem font sizes,
respectively.

The `ComputedTextBlock::needs_rerender` method has been modified to take
take two bool parameters:
```rust
    pub fn needs_rerender(
        &self,
        is_viewport_size_changed: bool,
        is_rem_size_changed: bool,
    ) -> bool {
        self.needs_rerender
            || (is_viewport_size_changed && self.uses_viewport_sizes)
            || (is_rem_size_changed && self.uses_rem_sizes)
    }
 ```
This ensures that text reupdates will also be scheduled if one of the text section's uses a viewport font size and the local viewport size changed, or if one of the text section's uses a rem font size and the rem size changed.

#### Limitations

There are some limitations because we don't have any sort of font style inheritance yet:

* "rem" units aren't proper rem units, and just based on the value of a resource. 
* "em" units are resolved based on inherited font size, so can't be implemented without inheritance support.

#### Notes

* This PR is quite small and not very technical. Reviewers don't need to be especially familiar with `bevy_text`. Most of the changes are to the examples.

* We could consider using `Val` instead of `FontSize`, then we could use `Val`'s constructor functions which would be much nicer, but some variants might not have sensible interpretations in both UI and Text2d contexts. Also we'd have to make `Val` accessible to `bevy_text`.

## Testing

The changes to the text systems are relatively trivial and easy to understand.  I already added a minor change to the `text` example to use `Vh` font size for the "hello bevy" text in the bottom right corner. If you change the size of the window, you should see the text change size in response. The text initially flickers before it updates because of some unrelated asset/image changes that mean that font textures aren't ready until the frame after the text update that changes the font size.

Most of the example migrations were automated using regular expressions, and there are bound to be mistakes in those changes. It's infeasible to check every single example thoroughly, but it's early enough in the release cycle that I don't think we should be too worried if a few bugs slip in.

---------

Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
2026-02-02 22:52:33 +00:00
ickshonpe 02c576215b FontSmoothing fixes (#22455)
# Objective

1. The `font_smoothing` field of `TextFont` is ignored in main
currently. Instead it always uses `FontSmoothing::Antialiased`.
2. The `FontSmoothing` enum is missing from the `bevy_text` prelude.
3. The `FontSmoothing` bug wasn't caught by the screenshot CI.

## Solution

1. Store the antialiasing mode in `ComputedTextBlock`, for use in
`TextPipeline::update_buffer`.
2. Add `FontSmoothing` to `bevy_text::prelude`.
3. Add a font smoothing example to `testbed_ui`'s `Text` scene.

## Testing

Check `testbed_ui`'s text scene.

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2026-01-15 20:07:00 +00:00
Aevyrie a88af65738 Contact Shadows (#22382)
# Objective

- Implement contact shadows to add fine shadow detail where shadow
cascades cannot.

## Solution

- Extend our existing pbr implementation using our existing raymarching
functions.

---

## Showcase

<img width="1824" height="1180" alt="image"
src="https://github.com/user-attachments/assets/e93b79c5-c596-4a9e-b94d-20bdde1d863b"
/>

<img width="1824" height="1180" alt="image"
src="https://github.com/user-attachments/assets/0fd7dffa-60b8-4b92-8fad-7f993d4d89dd"
/>


https://github.com/user-attachments/assets/e74b190d-9ae3-4aaf-97f0-b520930a0667


https://github.com/user-attachments/assets/e80ccb26-bbaa-4d25-a823-8ea12354c5b9


https://github.com/user-attachments/assets/b04f4b00-92bd-4a2f-b7dd-5157d8fbe0ab

<img width="1073" height="685" alt="image"
src="https://github.com/user-attachments/assets/b7629908-dd32-48db-8ee7-a4d2dd8f66c2"
/>

<img width="1073" height="685" alt="image"
src="https://github.com/user-attachments/assets/3de0258e-9191-4180-ac57-41b32e1205bd"
/>

<img width="1073" height="685" alt="image"
src="https://github.com/user-attachments/assets/951477f9-e9a9-426f-ae8d-18ae50cc7b85"
/>

<img width="1073" height="685" alt="image"
src="https://github.com/user-attachments/assets/2291453c-da57-4fcc-a6b0-f60f6eac6cbb"
/>

<img width="1073" height="685" alt="image"
src="https://github.com/user-attachments/assets/5820cdff-ea54-4294-b520-2a8d8dc24996"
/>

<img width="1073" height="685" alt="image"
src="https://github.com/user-attachments/assets/3ea16481-7689-4e99-87e2-1589f1532e4c"
/>

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: charlotte 🌸 <charlotte.c.mcelwain@gmail.com>
2026-01-13 21:51:39 +00:00
ickshonpe e5d4dfd7a6 Minimal Font Families, Font Queries, Collections, System Fonts, Stretch, and Slant support (#22156)
# Objective

Implement support for the remaining missing text features with minimal
changes.

## Solution

`TextFont` has been expanded to include new fields:
```rust
pub struct TextFont {
    pub font: FontSource,
    pub font_size: f32,
    pub weight: FontWeight,
    pub width: FontWidth,
    pub style: FontStyle,
    pub font_smoothing: FontSmoothing,
    pub font_features: FontFeatures,
}
```

FontSource has two variants: Handle, which identifies a font by asset
handle, and Family, which selects a font by its family name.

`FontWidth` is a newtype struct representing OpenType font stretch
classifications ranging from ULTRA_CONDENSED (50%) to ULTRA_EXPANDED
(200%).

`FontStyle` is an enum used to set the slant style of a font, either
`Normal`, `Italic`, or `Oblique`.

The system font support is very barebones. You load them using the
`CosmicFontSystem` resource:
```rust
font_system.db_mut().load_system_fonts()
```
Then they are available to be selected by family name using
`FontSource::Family`.

### Other changes

* `TextPipelines`'s `glyph_info` field has been removed. There is no
need to collect the section infos or perform any querys during text
layout updates, so that code has been removed as well.

* `update_text_layout_info` used some `try_for_each` with some nested
closures which was unnecessarily complicated again. They've been
replaced with a regular for loop.

* After font assets are loaded there's a new system
`load_font_assets_into_fontdb_system` that automatically adds them to
cosmic text's font database. Then they are available to be looked up by
family name as well as by asset handle.

* There aren't are performance motivated changes but layout updates seem
to be overall significantly more efficient now, with a slight regression
for very large numbers of short, single section text entities.

* Font texture atlases are no longer automatically cleared when the font
asset they were generated from is removed. There is no way to remove
individual fonts from cosmic text's `FontSystem`, so the font is still
accessible using the family name with `FontSource::family` and removing
the text atlases naively could cause a panic since rendering expects
them to be present.

## Testing

```
cargo run --example font_query
```
---

## Showcase

<img width="1229" height="591" alt="font-query"
src="https://github.com/user-attachments/assets/23f5aaa2-fdb8-4448-9b4e-9d65d6431107"
/>

---------

Co-authored-by: Thierry Berger <contact@thierryberger.com>
2026-01-03 22:38:53 +00:00
François Mockers 730b002260 fix testbeds with argh in wasm (#22339)
# Objective

- #22223  used argh in the testbed examples
- this compile in wasm but crashes when running them

## Solution

- Fix it like the other examples using argh
2026-01-01 19:47:31 +00:00
panpanpro888 9f02248af4 Add command line option to choose a starting scene in the `testbed_*' examples (#22223)
# Objective

- Fixes #22218

## Solution

- Use `argh` to check if you passed a scene name, and if you did, start
on that one instead of the default

## Testing

- Tested on my local machine, I don't see a reason why it would change
between different machines and/or platforms

---------

Co-authored-by: Bayley Foster <43776524+apekros@users.noreply.github.com>
Co-authored-by: François Mockers <francois.mockers@vleue.com>
2025-12-31 22:59:49 +00:00
ickshonpe 64c7bec406 Extra testbed_ui font cases (#22198)
# Objective

Modify the `testbed_ui` text scenes so it will catch bugs like #22191

## Solution

Add new cases to `testbed_ui`'s `text` scene displaying multiple text
sections with different fonts and weights with spaces and without
spaces.

## Showcase

<img width="1924" height="1127" alt="Screenshot 2025-12-19 142112"
src="https://github.com/user-attachments/assets/3247c0d7-cfca-45ac-88dd-b8a8a4266dff"
/>
2025-12-24 01:13:55 +00:00
Kevin Chen ed85f770c9 Adds ViewportCoords Scene to examples/testbed/ui, Removes viewport_debug example (#22050)
# Objective

- Closes #21806

## Solution

- Copies the setup contained in `spawn_with_viewport_coords` from
`viewport_debug` into its own scene in the ui testbed. The testbed
spawns a 1280 x 720 resolution window by default, so it looks the same.
I explicitly set the size anyway and set resizeable to false to
accommodate this new scene
- Removes the `viewport_debug` example (Although, tbh, I’m wondering if
it’s actually worth keeping around since it might be useful for
debugging for whatever reason. **Second opinions welcome** on the
deletion of `viewport_debug`)

## Testing

Ran `cargo run --example testbed_ui` and compared the new
`ViewportCoords` scene via screenshot to the `viewport_debug` example
(`cargo run --example viewport_debug`). They look the same.

---

## Showcase

To see the scene, checkout the branch and run `cargo run --example
testbed_ui`. Hit the Spacebar 12x to see the new scene.

<img width="1284" height="748" alt="Screenshot 2025-12-06 at 5 03 42 PM"
src="https://github.com/user-attachments/assets/265caf93-57d2-475e-b532-6c7f36074085"
/>
2025-12-16 16:52:15 +00:00
Greeble a3ad40d412 Alternative glTF coordinate conversion (#20394)
## Objective

Change glTF coordinate conversion to satisfy some common use cases while
dodging the more controversial aspects. This fixes #20621, but at the
cost of removing one feature.

## Summary

The Bevy glTF loader can optionally convert nodes and meshes from glTF's
"+Z forward" semantics to Bevy's "-Z forward". But the current
implementation [has
issues](https://github.com/bevyengine/bevy/issues/20621), particularly
with cameras and lights. It might also cause problems for users who want
to re-orient the scene as a whole while preserving the original node
semantics.

This PR replaces node conversion with a simpler correction to the scene
root and mesh entities. The new approach satisfies many use cases and
fixes the issues with cameras and lights. But it could be a regression
for some users.

## Background

There's been confusion over how glTF behaves and what users might want
from coordinate conversion. This section recaps the basic concepts,
glTF's semantics, the current loader behaviour, and some potential user
stories. Or you can skip to the next section if you want to get straight
to the changes.

<details>
<summary>Click to expand</summary>

### Coordinate Systems and Semantics

3D coordinate systems can have semantics assigned to their axes. These
semantics are often defined as a forward axis, an up axis, and a
[handedness](https://en.wikipedia.org/wiki/Right-hand_rule) - the side
axis is implicit in the other choices.

Bevy's standard semantics are "-Z = forward, +Y = up, right handed".
This standard is codified by the `forward` and `up` methods of
`Transform` and `GlobalTransform`, and by the renderer's interpretation
of camera and light transforms. There are debates about the standard and
whether users should be able to choose different semantics. This PR does
not account for those debates, and assumes that users want to follow the
current standard.

Other engines, DCCs, and file formats can have [different
semantics](https://mastodon.social/@acegikmo/113313928426095165). Unlike
Bevy, some vary their semantics by object type - a camera's forward axis
may not be the same as a light's. Some only specify an up axis, leaving
the forward and side axes unspecified.

Assets might not follow the standard semantics of their file format.
Static mesh hierarchies and skeletal animation rigs may even have
per-node or per-joint semantics - a character rig could be +Y forward in
the scene, while the head joint is +Z forward. One character rig might
have both feet +X forward, while another rig might have the left foot +X
forward and the right foot -X forward. This creates complexity, but also
creates jobs, so no-one can say if it's good or bad.

### Asset Loaders And Coordinate Conversion

Bevy currently has a glTF loader, and I'm assuming it will get in-repo
FBX and USD loaders at some point. These loaders are likely to follow a
common pattern:

- The files contain meshes, which correspond to Bevy `Mesh` assets and
skinned meshes.
- Bevy meshes can only have a single material, so what the file format
considers a single mesh might be multiple Bevy meshes.
- The files have a node hierarchy, where nodes roughly correspond to
Bevy entities with a `Transform`.
- Nodes can optionally be mesh instances, cameras, lights or skinned
mesh joints.
- The loader outputs the assets and a `Scene` with an entity hierarchy
that tries to match the file's node hierarchy.
- Some aspects of nodes (e.g. pivot transforms) can't be represented in
Bevy within a single entity.
- So a 1:1 mapping might not be possible - instead nodes become multiple
entities, or some data is lost (e.g. baking down pivot transforms).
- Users can choose to spawn the scene, or they can ignore it and use the
assets directly.

Users may want asset loaders that convert assets to Bevy's standard
semantics, so `Transform::forward` matches the asset. But the details of
conversion can be contentious - users may want some parts of the scene
to be converted differently from other parts, and assets may have
ambiguities than can only be resolved by the user. There will never be a
simple "it just works" option, although there could be a least worst
default that satisfies the biggest group of users.

Converting in the loader is not the only option. The user could edit the
assets themselves or run a conversion script in DCC. But that's a pain -
particularly for users who rely on asset packs and don't have DCC
experience. Another option is to implement an asset transform that does
coordinate conversion. But having the options right there in the loader
is convenient.

### User Stories

For coordinate conversion in the loader, some user stories might be:

- "I want to spawn a scene on an entity with Bevy semantics and have it
look right."
- This is probably the most common case - the user wants to do
`SceneRoot(load("my.gltf"))` and have it visually match the entity's
`Transform::forward()`, and cameras and lights should do the right
thing.
- The user might not care about the semantics of mesh assets and nodes
in the scene - they just want the scene as a whole to look right.
- "I want to spawn a scene, and convert some or all of the nodes to Bevy
semantics."
- The user might have nodes in their scene that they want to animate
manually or hook up to other systems that assume Bevy semantics.
- That becomes easier if the loader can convert the node's forward to
match `Transform::forward()`.
- Conversely, some users might want nodes to stay as they are
(particularly skeletal animation rigs).
- "I want a mesh asset that's converted to Bevy semantics. I'm not using
a scene."
- Maybe the user is doing `Mesh3d(load("mesh.gltf#Mesh0"))` and wants it
to match the entity's forward.
- Or this is the first stage of an asset pipeline and the remaining
stages expect Bevy semantics.
- "I don't want the loader to touch anything."
- Maybe they've already converted the file, or want to convert it
post-load, or don't want to use Bevy semantics at all.
- "I want one of the other conversion stories, but the loader should
convert to my chosen semantics rather than Bevy's".
    - Z-up is not a crime.

### glTF Semantics

glTF [scene
semantics](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#coordinate-system-and-units)
are "+Z = forward, +Y = up, right handed". This is almost the same as
Bevy, except that scene forward is +Z instead of Bevy's -Z.

Some glTF assets do not follow the spec's scene semantics. The Kenney
asset packs use a mix of +Z and -Z forward. At least [one of the Khronos
sample
assets](https://github.com/KhronosGroup/glTF-Sample-Assets/tree/main/Models/Duck)
uses +X forward. That said, the majority of Kenney assets and almost all
the Khronos sample assets I tested do follow the spec.

glTF [camera
node](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#view-matrix)
and [light
node](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_lights_punctual/README.md#adding-light-instances-to-nodes)
semantics are different from glTF scene semantics - they're -Z forward,
same as Bevy.

The glTF spec doesn't explicitly say if non-camera/light nodes and mesh
buffers have semantics. I'm guessing that some users will have nodes and
meshes that follow the spec's scene semantics, and might want them
converted to Bevy semantics. But as noted in the user stories, it's
likely that other users will have different needs.

glTF and Bevy allow a single node/entity to be both a mesh and a camera
or a light. This only makes sense if the user intends the mesh to have
the same semantics as cameras and lights. I think it's very unlikely
that significant numbers of users will want support for this combination
- many other DCCs, file formats and engines don't support it at all.

### How The Bevy glTF Loader Works

The loader maps glTF nodes to Bevy entities. It also adds entities for
two cases:

1. A single "scene root" entity is added as a parent of the glTF root
nodes.
- Note that this is not the user's entity with the `SceneRoot` component
- the scene root entity is a child of that entity.
2. Mesh primitive entities are added as a child of each glTF mesh node.
    - In glTF, a single mesh node can contain multiple primitives.
- But in Bevy a mesh component can only contain a single primitive, so
one entity can't contain multiple primitives.
- So, for each primitive, Bevy adds a child entity with a mesh
component.

A single branch of the resulting scene hierarchy might look like this:

- User entity with `SceneRoot` component.
    - Scene root entity.
        - glTF root node entity.
            - glTF intermediate node entities.
- glTF mesh node entity (does not contain `Mesh3d` component)
- Mesh primitive entities (does contain `Mesh3d` component).

### glTF Loader Changes In 0.17

In Bevy 0.16, the only user story supported by the glTF loader was "no
conversion". During the 0.17 cycle, #19633 and some follow up PRs
implemented an option that converts nodes, meshes and animation tracks.

The changes do satisfy some user stories, including the common "convert
scene semantics" (mostly) and "convert mesh semantics". But there's some
problems (#20621):

- The conversion depends on converting both nodes and meshes.
- Some users might want to convert the scene without converting nodes
and/or meshes.
- Light and camera nodes get complicated.
- glTF camera/light nodes already match Bevy semantics, so they need a
counter-conversion (since their parent might have been converted).
- Animation tracks for lights and cameras are not correctly converted.
        - (Counterpoint: This is fixable at the cost of some complexity)
    - Child nodes of lights and cameras are not correctly converted.
        - (Counterpoint: Also fixable, and probably a niche case?)
- The conversion can't support a node that's a mesh instance and also a
light and/or a camera.
- (Counterpoint: As mentioned earlier, this is probably a very niche or
non-existent use case.)

</details>

## Solution

The big change in this PR is the removal of node conversion. Instead,
corrective transforms are applied to the scene root entity and mesh
primitive entities.

Before this PR:

- Scene root entity. 
    - glTF root node entity. <-- CONVERTED
        - glTF intermediate node entities. <-- CONVERTED
            - glTF mesh node entity. <-- CONVERTED
                - Mesh primitive entities.

After this PR:

- Scene root entity. <-- CORRECTIVE (if scene conversion enabled)
    - glTF root node entity. 
        - glTF intermediate node entities. 
            - glTF mesh node entity.
- Mesh primitive entities. <-- CORRECTIVE (if mesh conversion enabled)

The result is visually the same even though the scene internals are
different. Cameras and lights now work correctly, including when
animated.

The new conversion is also simpler. There's no need to convert
animations, and the scene part of the conversion only changes a single
entity:

```diff
+let world_root_transform = convert_coordinates.scene_conversion_transform();

 let world_root_id = world
-    .spawn((Transform::default(), Visibility::default()))
+    .spawn((world_root_transform, Visibility::default()))
     .with_children(|parent| {
         for node in scene.nodes() {
```

Removing node conversion might be a regression for some users. My guess
is that most users just want to spawn a scene with the correct
orientation and don't worry about individual node transforms, so on
balance this PR will be win. But I don't have much evidence to back that
up. There might also be a path to adding node conversion back in as an
option - see the "Future" section below.

The previous conversion option -
`GltfPlugin::use_model_forward_direction` - has been split into two
separate options for scene and mesh conversion.

```diff
 struct GltfPlugin {
     ...
-    use_model_forward_direction: bool,
+    convert_coordinates: GltfConvertCoordinates,
 }
```
```rust
struct GltfConvertCoordinates {
    scenes: bool,
    meshes: bool,
}
```

This might be turn out to be unnecessary flexibility, but I think it's
the safer option for now in case users have unexpected needs. Both
options are disabled by default.

### Testing

I've tested various examples and glTFs with each combination of options,
including glTFs with animated cameras and lights.

```sh
# Visually the same as current Bevy *without* conversion.
cargo run --example scene_viewer "assets/models/faces/faces.glb"
cargo run --example scene_viewer "assets/models/faces/faces.glb" --convert-mesh-coordinates

# Visually the same as current Bevy *with* conversion.
cargo run --example scene_viewer "assets/models/faces/faces.glb" --convert-scene-coordinates
cargo run --example scene_viewer "assets/models/faces/faces.glb" --convert-scene-coordinates --convert-mesh-coordinates

cargo run --example animated_mesh
```

## Future

<details>
<summary>Click to expand</summary>

This PR removes node conversion, which is a desirable feature for some
users. There are a couple of ways it could be added back as an option.

The difficult part of node conversion is how to support camera and light
nodes. glTF's camera/light semantics already match Bevy's -Z forward, so
simply converting every node from +Z to -Z forward will leave camera and
light nodes facing the wrong direction.

The obvious solution is to special case camera/light node transforms -
this is what the 0.17 conversion tries to do. But it's surprisingly
complex to get right due to animation, child nodes, and nodes that can
be meshes and cameras and lights. E.g. children of cameras and lights
need a counter-conversion applied to their transform and animation
tracks.

For cameras, an alternative would be to split them multiple entities.
The existing entity would correspond to the glTF node and be converted
like every other node. But the Bevy `Camera` component would be on a new
child entity and have a corrective transform.

Before:

- Parent glTF node entity.
- Camera glTF node entity with `Camera` component and animated
transform.
    - glTF node parented to camera node.

After:

- Parent glTF node entity.
  - Camera glTF node entity with animated transform.
    - New child entity with `Camera` component and corrective transform.
    - glTF node parented to camera node.

Lights are already set up this way, so they only need the corrective
transform.

This approach is simpler since nodes are treated uniformly. And it's
arguably a better reflection of the glTF format - glTF cameras are kind
of a separate thing from nodes, and can be given a name that's different
to their node's name. So it could be better for some users.

The downside is that the glTF node entity might have the wrong semantics
from the perspective of some users (although not all). And it will be
annoying for users who currently assume the `Camera` component is on the
node entity.

</details>

## Alternatives

<details>
<summary>Click to expand</summary>

### What About The Forward Flag Proposal?

There's a [proposal](https://github.com/bevyengine/bevy/pull/20135) to
allow per-transform semantics, aka the "forward flag". This means the
axis of `Transform::forward()` and others would depend on a variable in
the `Transform`. In theory the forward flag might avoid the need for
coordinate conversion in the loader. But whether that works in practice
is unclear, and the proposal appears to be stalled.

### What Do Other Engines Do?

[Godot's
semantics](https://docs.godotengine.org/en/4.4/tutorials/assets_pipeline/importing_3d_scenes/model_export_considerations.html#d-asset-direction-conventions)
are the same as the glTF standard. Godot doesn't offer any conversion
options.

Unreal's default semantics are "+X forward, +Z up, left handed", except
meshes are typically "+Y forward, +Z up". Their glTF importer converts
nodes and meshes to Unreal's mesh semantics - this is done by swapping
the Y and Z axes, which implicitly flips the X for handedness. So
Unreal's approach is actually closer to the current main approach of
node + mesh conversion, versus this PR's scene + mesh conversion. The
Unreal importer also supports a custom scene/mesh rotation and
translation that's applied after normal conversion. There's no option to
disable conversion.

</details>

---------

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
Co-authored-by: Alice I Cecile <alice.i.cecile@gmail.com>
2025-12-16 00:34:02 +00:00
shivanandu b58ecf2ac3 Add sprite slicing scene to testbed_2d example (#22089)
# Objective

- Sprite slicing doesn't have any example with the screenshot CI.
- Fixes #22083

## Solution

- Added a new `sprite_slicing` module to `examples/testbed/2d.rs`

## Testing
- Ran the testbed with `cargo run --example testbed_2d`
- Cycled through all scenes using spacebar
- Verified the sprite slicing scene displays correctly with both
original and sliced sprites
- Confirmed labels and positioning are correct

---

## Showcase

<img width="1372" height="755" alt="Screenshot From 2025-12-11 15-41-23"
src="https://github.com/user-attachments/assets/8f5a6223-78bb-4670-b23e-280e003df324"
/>
2025-12-14 21:26:13 +00:00
Kevin Chen d44b9f8694 Adds UIDebug Overlay centered scene to examples/testbed/ui (#22052)
# Objective

- Fixes #22019 

## Solution

- Adds a new scene in the ui testbed that tests the generation of the Ui
Debug Overlay. It only is viewable if you run the example with
`--features bevy_ui_debug`.
- Added a way to override the color used by the overlay to ensure that
screenshots are consistent between CI runs (the line colors are
generated based on the `Entity`, which changes every time you change the
scene.)
- Added the `--features bevy_ui_debug` flag to `example-run.yml`,
ensuring that screenshots and their validations take this new scene into
account. (I assumed I’m not supposed to add this to
`validation-jobs.yml` under `run-examples-on-wasm`, but if I’m supposed
to, let me know and I can add it. I figured a debug feature does not
need that specific validation).

## Testing

- I ran the command `cargo run --example testbed_ui --features
bevy_ui_debug` and verified that debug lines showed up for regular
outlines, for a node with `Visibility::Hidden` with `show_hidden =
true`, and that clipped areas have outlines with `show_clipped = true`.
I carouseled through all the scenes a couple of times
- I also ran `cargo run --example testbed_ui ` and made sure nothing was
ruined after multiple carousels through all the scenes.

---

## Showcase

`cargo run --example testbed_ui --features bevy_ui_debug` , press
spacebar 11x to see the scene.

<img width="1282" height="750" alt="Screenshot 2025-12-06 at 10 03
25 PM"
src="https://github.com/user-attachments/assets/f76ef3ac-b762-4eef-9843-573f362fe45a"
/>
2025-12-08 22:31:47 +00:00
Kevin Chen c4b68363d8 Add a UiTransform centered scene to examples/testbed/ui (#21974)
# Objective

Fixes #21815 

## Solution

- Adds a new scene to `examples/testbed/ui` called `Transformations`
that calls some basic `UiTransform`s on Nodes.

This is my first PR for Bevy!

## Testing

I ran the example via console to test out the scene.

Tested on Desktop MacOS 15.7.1

## Showcase

<img width="902" height="780" alt="Screenshot 2025-11-29 at 11 29 52 AM"
src="https://github.com/user-attachments/assets/602ab485-61dd-4887-a0ad-0624b3d79db8"
/>

To view, run in console: `cargo run --package bevy --example testbed_ui`
Press spacebar 11x until you see the new scene.
2025-11-29 20:54:55 +00:00
ickshonpe a37c14ce95 Add BorderRadius to Node (#21781)
# Objective

There was discussion in the `Next Generation Scene/UI` about adding
`BackgroundColor` to `Node`. I don't know about that, but it reminded me
that border radius isn't part of `Node`. All the other properties that
affect a `Node`'s shape are there, border radius should be there too.

## Solution

* Add a `border_radius: BorderRadius` field.
* Remove the `Component` derive from `BorderRadius`.

## Testing

The internal changes are relatively trivial. There could be mistakes in
the examples though, because of the large number of changes.
2025-11-13 23:41:52 +00:00
atlv 6b34012ffa Rename cuboid to cube (#21393)
# Objective

- Gizmos::cuboid is for drawing cubes, even the docs say so. A cuboid
drawing function should take Cuboid as input.

## Solution

- Rename ::cuboid to ::cube, making way for an actual cuboid drawing
function.

## Testing

- ci
2025-10-06 21:20:13 +00:00
Talin f07c12570a Renamed bevy_core_widgets to bevy_ui_widgets. (#20944)
Renamed `CoreXXX` components to `XXXBehavior`.
Fixes: #20664

@alice-i-cecile @cart
2025-09-10 23:25:51 +00:00
Carter Anderson 4d74baf1ae BufferedEvent -> Message Rename (#20953)
This renames the concept of `BufferedEvent` to `Message`, and updates
our APIs, comments, and documentation to refer to these types as
"messages" instead of "events". It also removes/updates anything that
considers messages to be "observable", "listenable", or "triggerable".

This is a followup to https://github.com/bevyengine/bevy/pull/20731,
which omitted the `BufferedEvent -> Message` rename for brevity.

See that post for rationale.
2025-09-10 21:04:15 +00:00
Carter Anderson eda118d033 Event Rearchitecture (#20731)
There is general consensus that our terminology for Events, "entity
events", Observers, and BufferedEvents needs clarity. Additionally, many
of us also agree that the current Observer system would benefit from
additional static-ness: currently it is assumed that you can use events
in pretty much any context, and they all go through the exact same code
path.

Alice put forth a proposal to [Overhaul
Observers](https://hackmd.io/@bevy/rk4S92hmlg), and we have already
partially implemented it for 0.17. I think it does a great job of
outlining many of the issues at play, and it solves them reasonably
well. But I _also_ think the proposed solution isn't yet ideal. Given
that it is already partially implemented for 0.17, it is a breaking
change, _and_ given that we have already broken the Observer API a
number of times, I think we need to sort this out before the next
release.

This is a big changeset, but it is _largely_ just a reframing of what is
already there. I haven't fundamentally changed the behaviors. I've just
refined and constrained in a way that allows us to do what we are
currently doing in a clearer, simpler, and more performant way.

First, I'll give some quick notes on Alice's proposal (which you all
should read if you haven't yet!):
### Notes on Alice's Proposal
- I like the move toward a more static API
- I think we've gone too far down the "separate terminology" path. The
proposal introduces a zoo of apis, terms, and "subterms". I think we
need to simplify our concepts and names to make this all easier to talk
about and use in practice.
- BroadcastEvent feels like the wrong name. EntityEvent is also
"broadcast" in the exact same way
- BufferedEvent is a completely different system than EntityEvent and
BroadcastEvent. This muddles concepts too much. It needs its own
standalone, single-word concept name.
- "Universal observers": I think this should be fully context driven,
rather than needing encoding in the API.
- I agree we can't get rid of buffered events, and that merging them
with "broadcast events" isn't helpful
- I'm not quite sure how we'd make the proposed PropagateEvent subtrait
work transparently. This can't be "layered on top" as a trait. It needs
to be baked in at more fundamental level.
* I don't like `app.add_broadcast_observers()`,
`app.add_universal_observers()`, `Observer::entity_observer`,
`Observer::broadcast`, etc. The `On` event should statically determine
whether an observer is an "entity observer" or a "broadcast" Observer.
This would already be encoded in the type system and is therefore
something we can do on the developer's behalf. Likewise, any observer
being registered at a top level is inherently _not_ a specific entity
observer. All of these variants serve to make users guess and poke
around in a way that is unnecessary. I want simple one word concept
names, single constructors, etc.
### Proposed Principals
- Static-ness:
- Events should only be usable in the context they were defined to be
used.
- When triggered, Observers should *only* have access to fields and
behaviors that are relevant:
- Dont return Option or PLACEHOLDER: the field or function shouldn't
exist
- Entity events that don't support propagation shouldn't expose that
functionality
- Don't do unnecessary work at runtime
- Event triggers shouldn't branch through every potential event code
path
- Don't clone potentially large lists of event context unnecessarily
(Ex: we currently clone the component list for every observer
invocation)
- Minimize codegen
	- Don't recompile things redundantly.
	- Don't compile unnecessary code paths.
- Clear and Simple
- Minimize the number of concept names floating around, and lock each
concept down heavily to a specific context
- I'm convinced at this point that "buffered events" and "observer
events" sharing concept names is wrong. We need two clean and clear
terms, and I'm willing to give "buffered events" a slightly worse name
if it means "observer events" can be nicer.
- Don't throw the concept name "Event" out ... it is a very good name.
Instead, constrain it to one specific thing.
	- Minimize our API surface
- Events contain all context, including what used to be the "target".
This lets people define the "target" name that makes the most sense for
the context, and lets the documentation fully describe the context of
that "target".
### Concepts
- **Event** (the thing you "observe")
- Rationale: "Event" is the clear choice for this concept. An "event"
feels like something that happens in real time. "Event observers" are
things that observe events when they occur (are triggered).
Additionally, this is the concept that "propagates", and "event
propagation" is a term people understand.
- **Trigger**: (the verb that "causes" events to happen for targets).
Events are Triggered. This can include additional context/ data that is
passed to observers / informs the trigger behavior. Events have
_exactly_ one Trigger. If you want a different trigger behavior, define
a new event. This makes the system more static, more predictable, and
easier to understand and document. `world.trigger_ref_with` makes it
possible to pass in mutable reference to your own Trigger data, making
it possible to customize the input trigger data and read out the final
trigger data.
- **Observer** (the thing that "observes" events): An event's `Trigger`
determines which observers will run.
- **Event Types**: You can build any "type" of event. The concept of a
"target" has been removed. Instead, define a `Trigger` that expects a
specific kind of event (ex: `E: EntityEvent`).
- **EntityEvent** We add a new `EntityEvent` trait, which defines an
`event.entity()` accessor. This is used by the `Trigger` impls :
`EntityTrigger`, `PropagateEntityTrigger`, and
`EntityComponentsTrigger`.
- **Message** (the buffered thing you "read" and "write")
- `Message` is a solid metaphor for what this is ... it is data that is
written and then at some later point read by someone / something else. I
expect existing consumers of "buffered events" to lament this name
change, as "event" feels nicer. But having a separate name is within
everyone's best interest.
	- **MessageReader** (the thing that reads messages)
	- **MessageWriter** (the thing that writes messages)
### The Changes
- `Event` trait changes
	- Event is now used exclusively by Observers
- Added `Event::Trigger`, which defines what trigger implementation this
event will use
- Added the `Trigger` trait
- All of the shared / hard-coded observer trigger logic has been broken
out into individual context-specific Trigger traits.
- "Trigger Targets" have been removed.
- Instead, Events, in combination with their Trigger impl, decide how
they will be triggered. In general, this means that Events now include
their "targets" as fields on the event.
- APIs like `trigger_targets` have been replaced by `trigger`, which can
now be used for any `Event`
- `EntityEvent` trait changes
- Propagation config has been removed from the `EntityEvent` trait. It
now lives on the `Trigger` trait (specifically the
`PropagateEntityTrigger` trait).
- `EntityEvent` now provides `entity / entity_mut` accessors for the
Event it is implemented for
- `EntityEvent` defaults to having no propagation (uses the simpler
`EntityTrigger`)
- `#[entity_event(propagate)]` enables the "default" propagation logic
(uses ChildOf). The existing `#[entity_event(traversal = X)]` has been
renamed to `#[entity_event(propagate = X)`
- Deriving `EntityEvent` requires either a single `MyEvent(Entity)`, the
`entity` field name (`MyEvent { entity: Entity}`), or `MyEvent {
#[event_entity] custom: Entity }`
- Animation event changes
- Animation events now have their own `AnimationEvent` trait, which sets
the `AnimationEventTrigger`. This allows developers to pass in events
that _dont_ include the Entity field (as this is set by the system). The
custom trigger also opens the doors to cheaply passing in additional
animation system context, accessible through `On`
- `EntityComponentsTrigger`
- The built in Add/Remove/etc lifecycle events now use the
`EntityComponentsTrigger`, which passes in the components as additional
state. This _significantly_ cuts down on clones, as it does a borrow
rather than cloning the list into _each_ observer execution.
	- Each event now has an `entity` field.
- Style changes
- Prefer the event name for variables: `explode: On<Explode>` not
`event: On<Explode>`
- Prefer using the direct field name for the entity on entity events,
rather than `event.entity()`. This allows us to use more specific names
where appropriate, provides better / more contextual docs, and coaches
developers to think of `On<MyEvent>` _as_ the event itself.

Take a look at the changes to the examples and the built-in events to
see what this looks like in practice.

### Downsides
- Moving the "target" into the event adds some new constraints:
- Triggering the same event for multiple entities requires multiple
trigger calls. For "expensive" events (ex: lots of data attached to the
event), this will be more awkward. Your options become:
		-  Create multiple instances of the event, cloning the expensive data
- Use `trigger_ref`, and mutate the event on each call to change the
target.
- Move the "expensive" shared data into the Trigger, and use
`trigger_ref_with``
- We could build a new EntityEvent method that abstracts over the "event
mutation" behavior and provides something like the old `trigger_target`
behavior.
- Use a different `EntityTargetTrigger` (not currently provided by bevy,
but we could), which brings back the old behavior. This would be used
with `trigger_with` to replicate the old pattern:
`world.trigger_with(MyEvent, [e1, e2].into())` (or we could make the
`into()` implicit)
- Bubbling the event involves mutating the event to set the entity. This
means that `trigger_ref` will result in the event's
`EntityEvent::entity()` being the final bubbled entity instead of the
initial entity.
- Some APIs (trivially) benefit from the "target entity" being separate
from the event. Specifically, this new API requires changes to the
"Animation Event" system in AnimationPlayer. I think this is actually a
good change set, as it allows us to:
- Cheaply expose more animation state as part of a new
AnimationEventTrigger impl
- Move that "implict" entity target provided by the AnimationPlayer into
the AnimationEventTrigger
- Encode the "animation event trigger-ness" of the event into the type
itself (by requiring `#[event(trigger = AnimationEventTrigger)]`)
- By not implementing Default for AnimationEventTrigger, we can block
animation events from being fired manually by the user.

### Draft TODO
- [x] Fill in documentation and update existing docs
- [ ] Benchmark: I expect this impl to be significantly faster. There
might also be tangible binary size improvements, as I've removed a lot
of redundant codegen.
- [x] Update release notes and migration guides

### Next Steps
- The `BufferedEvent -> Message` rename was not included to keep the
size down.

Fixes #19648

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
2025-09-09 23:48:55 +00:00
atlv f6b77e4e49 bevy_post_process (#20778)
# Objective

Split out post process effects from bevy_core_pipeline because they are
not core pipelines.

## Solution

@IceSentry proposed something like this, not sure if the split is
exactly as he envisioned but this seems reasonable to me.

The goal is to move absolutely everything possible out of
bevy_core_pipelines to unblock bevy_pbr/bevy_sprite_render compilation.

Future PRs may attempt to move more little bits out.

## Testing
2025-09-05 04:26:08 +00:00
Jan Hohenheim b43a73df3f Rename DespawnOnExitState to DespawnOnExit (#20872)
# Objective

- `StateScoped` was renamed to `DespawnOnExitState`, and we introduced
`DespawnOnEnterState`
- This is redundant: the type it wraps is already a state
- Often, state enums have `State` in their names, leading to stutter:
`DespawnOnExitState(GameState::Gameplay)`
- This component is *very* common in games. The longer name makes it
clunkier to use, so we should be careful when expanding it. I think the
added clarity is good, but we can do better.

## Solution

- Compromise to `DespawnOnExit`
- Do the same for `DespawnOnEnter`

## Testing

- CI
2025-09-04 21:13:46 +00:00
Amedo 6eb011c30c Replace from_ constructors on TextFont with From impls (#20450)
# Objective

- Closes #20353

## Solution

- Removed `TextFont::from_font` and `TextFont::from_line_height`.
- Updated `examples/testbed/2d.rs` to use the `Form` impl.
- Added migration guide.
2025-09-04 20:05:32 +00:00
ickshonpe c365f97cb9 another text color fix (#20856)
# Objective

Fixes #20854

## Solution

Query for the next color on span changes before queuing the next glyph.

## Testing

Added two more cases to `testbed_ui`'s text example, the three lines of
coloured text should all look identical:

```cargo run --example testbed_ui```

<img width="487" height="234" alt="text-color" src="https://github.com/user-attachments/assets/78d10141-9b2f-4a57-9b64-eda62da46db5" />
2025-09-03 20:54:49 +00:00
ickshonpe e46fd71d80 Add coloured text to the ui testbed example's text module (#20836)
# Objective

Add some coloured text to the UI testbed example.
2025-09-02 19:46:00 +00:00
TheBlckbird 13877fa84d Add a new trait to accept more types in the Val-helper functions (#20551)
# Objective

- Allow the `Val`-helper functions to accept more types besides just
`f32`

Fixes #20549

## Solution

- Adds a new trait that can be implemented for numbers
- That trait has a method that converts `self` to `f32`

## Testing

- I tested it using Rust's testing framework (although I didn't leave
the tests in, as I don't deem them important enough)

<details>
  <summary>Rust test</summary>

```rust
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_val_helpers_work() {
        let p = px(10_u8);
        assert_eq!(p, Val::Px(10.0));

        let p = px(10_u16);
        assert_eq!(p, Val::Px(10.0));

        let p = px(10_u32);
        assert_eq!(p, Val::Px(10.0));

        let p = px(10_u64);
        assert_eq!(p, Val::Px(10.0));

        let p = px(10_u128);
        assert_eq!(p, Val::Px(10.0));

        let p = px(10_i8);
        assert_eq!(p, Val::Px(10.0));

        let p = px(10_i16);
        assert_eq!(p, Val::Px(10.0));

        let p = px(10_i32);
        assert_eq!(p, Val::Px(10.0));

        let p = px(10_i64);
        assert_eq!(p, Val::Px(10.0));

        let p = px(10_i128);
        assert_eq!(p, Val::Px(10.0));

        let p = px(10.3_f32);
        assert_eq!(p, Val::Px(10.3));

        let p = px(10.6_f64);
        assert_eq!(p, Val::Px(10.6));
    }
}
```
</details>

---

## Showcase

```rust
// Same as Val::Px(10.)
px(10);
px(10_u8);
px(10.0);
```
2025-08-29 20:18:57 +00:00
Carter Anderson 5058f8a9e6 Improve On Terminology (#20648)
# Objective

Fixes #19263 (and expands on it)

Within `Observers`, we have started to distance ourselves from the
"trigger" terminology. Specifically, we have renamed `Trigger` to `On`.
I think this was a very good move, but we're currently in an awkward
middle ground state. Users interact with `On` as if it were an event:
`On<E>` exposes the event and derefs directly to it. I think we should
embrace this mindset fully, in the interest of clarity.

## Solution

- Rename all `trigger: On<SomeEvent>` cases to `event: On<SomeEvent>`.
- Rename `On::target` to `On::entity`. This reads _much_ better when
writing `query.get(event.entity())` and pairs more effectively with the
`EntityEvent` terminology.
- Rename `On::original_target` to `On::original_entity`, for the same
reasons.
- Take advantage of the `Deref` behavior where appropriate

```rust
// Before
entity.observe(|trigger: On<Explode>| {
  println!("{} exploded!", trigger.target());
})

// After
entity.observe(|event: On<Explode>| {
  println!("{} exploded!", event.entity());
})
```
2025-08-21 08:54:28 +00:00
Greeble 590da83c24 Fix glTF coordinate conversion not converting mesh bounds (#20608)
glTF coordinate conversion is applied to mesh assets, but not their
bounds:

<img width="1602" height="939" alt="image"
src="https://github.com/user-attachments/assets/b2bd0c4b-c9aa-4d53-b33d-c3463af7480e"
/>

After the fix:

<img width="1602" height="939" alt="image"
src="https://github.com/user-attachments/assets/ffb40e11-14e4-427f-adfb-5007e6b2cb0a"
/>

The PR also adds the above scene to `testbed_3d`.

## Testing

```sh
cargo run --example testbed_3d
```

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-08-17 16:38:42 +00:00
atlv 03dd839b82 Use bevy::camera in examples instead of bevy::render::camera re-export (#20477)
# Objective

- Prepare for removing re-exports

## Solution

- title

## Testing

- cargo check --examples
2025-08-09 21:09:48 +00:00