Commit Graph

824 Commits

Author SHA1 Message Date
Patrick Walton 185712fbef Add support for normal maps, metallic-roughness maps, and emissive maps to clustered decals. (#22039)
This commit expands the number of textures associated with each
clustered decal from 1 to 4. The additional 3 textures apply normal
maps, metallic-roughness maps, and emissive maps respectively to the
surfaces onto which decals are projected.

Normal maps are combined using the [*Whiteout* blending method] from
SIGGRAPH 2007. This approach was chosen because, subjectively, it
appeared better than the more complex [*reoriented normal mapping*
(RNM)] approach. Additionally, *Whiteout* normal map blending is
commutative and associative, unlike RNM, which is a useful property for
our decals, which are currently applied in an unspecified order. (The
fact that the order in which our decals are applied is unspecified is
unfortunate, but is a long-standing issue and should probably be fixed
in a followup.) In particular, commutativity is desirable because
otherwise one must specify which normal map is the *base* normal map and
which normal map is the *detail* normal map, but that's not a policy
decision that Bevy can unconditionally make, as decals aren't necessary
more detailed than the base normal map. (For instance, consider a bullet
hole decal embedded in a wall with a subtle rough texture; one might
reasonably argue that the base material's normal map is the detail map
and the bullet hole is the base map, even though the bullet hole's
normal map comes from a decal.)

Note that, with a custom material shader, it's possible for application
code to use the decal images for arbitrary other purposes. For example,
with a custom shader an application might use the metallic-roughness map
as a clearcoat map instead if it has no need for a metallic-roughness
map on a decal. And, of course, a custom material shader could adopt RNM
blending for decals if it wishes.

A new example, `clustered_decal_maps`, has been added. This example
demonstrates the new maps by spawning clustered decals with maps
randomly over time and projecting them onto a wall.

<img width="2564" height="1500" alt="Screenshot 2025-12-05 095953"
src="https://github.com/user-attachments/assets/255fca64-2b42-4794-a367-14336d023310"
/>
2025-12-09 18:14:55 +00:00
DuckyBlender 8a0367e7eb Add vertical slider support to bevy_ui_widgets slider (#21827)
# Objective

- Fixes the issue of vertical sliders not being functional. Previously,
when creating a vertical slider, the slider drag behavior was still
horizontal, meaning dragging left/right would change the value instead
of dragging up/down. Additionally, clicking on the slider track was
offset and didn't correctly map to the clicked position.

## Solution

The slider widget now automatically detects its orientation based on the
node's dimensions (`height > width` for vertical, otherwise horizontal)
and adjusts its interaction behavior accordingly:

1. **Orientation Detection**: Added automatic detection of slider
orientation by comparing `node.size().y` to `node.size().x` in both
`slider_on_pointer_down` and `slider_on_drag` functions.

2. **Drag Direction Fix**: 
- For vertical sliders, the drag calculation now uses the Y-axis
(`distance.y`) instead of X-axis
- The Y coordinate is properly inverted (since screen Y increases
downward) to match expected behavior (dragging up increases value)
- Thumb size calculation uses `thumb.size().y` for vertical sliders
instead of always using `thumb.size().x`

3. **Click Position Fix**:
- Fixed coordinate conversion from Bevy's center-origin coordinate
system to top/left-origin coordinates
- For vertical sliders: converts `local_pos.y` from `[-height/2,
+height/2]` to `[0, height]` before calculating the slider value
   - Accounts for thumb size offset to center the calculation properly
- Inverts the Y coordinate for vertical sliders since Y increases
downward

4. **Track Size Calculation**: Uses `node.size().y - thumb_size` for
vertical sliders and `node.size().x - thumb_size` for horizontal sliders
when calculating the available track space.

The changes are backward compatible - horizontal sliders continue to
work exactly as before, and the orientation detection is transparent to
users of the API.

## Testing

- **Manual Testing**: Created test application with both vertical and
horizontal sliders to verify:
- Vertical sliders respond correctly to vertical drag movements (up =
increase, down = decrease)
- Horizontal sliders continue to work correctly with horizontal drag
movements
- Clicking anywhere on the slider track correctly snaps to that position
for both orientations
  - Thumb positioning updates correctly during drag operations
  - Multiple sliders can coexist without interfering with each other

- **Edge Cases Tested**:
  - Clicking at the very top/bottom of vertical sliders
  - Clicking at the very left/right of horizontal sliders
  - Dragging from one extreme to the other
  - Rapid clicking and dragging interactions

**Areas that may need more testing:**
- Sliders with non-standard aspect ratios (very wide vertical sliders or
very tall horizontal sliders)
- Sliders with custom transforms/rotations applied
- Sliders in nested UI hierarchies with complex transforms

**How reviewers can test:**
1. Create a vertical slider (height > width) and verify:
   - Dragging up increases the value
   - Dragging down decreases the value
   - Clicking anywhere on the track snaps to that exact position
2. Create a horizontal slider (width > height) and verify it still works
as before
3. Test with multiple sliders of both orientations simultaneously

**Platforms tested:**
- macOS (Apple Silicon)

## Showcase

### Before
- Vertical sliders were unusable - dragging would move horizontally
instead of vertically
- Clicking on vertical slider tracks was offset, with clicks near the
bottom snapping to the middle instead


https://github.com/user-attachments/assets/9bda83e7-f46b-4626-9df3-a558526a8ab2



### After
- Vertical sliders work correctly with intuitive up/down drag behavior
- Clicking anywhere on the slider track accurately snaps to the clicked
position
- Both vertical and horizontal sliders work seamlessly together


https://github.com/user-attachments/assets/cca24288-4cbc-4ceb-828f-9ce7a735ade0



### Code Example

```rust
// Vertical slider - now works correctly!
commands.spawn((
    Node {
        width: Val::Px(12.0),
        height: Val::Px(300.0),  // height > width = vertical
        ..default()
    },
    Slider::default(),
    SliderValue(50.0),
    SliderRange::new(0.0, 100.0),
    // ... thumb and track children
));

// Horizontal slider - continues to work as before
commands.spawn((
    Node {
        width: Val::Px(300.0),
        height: Val::Px(12.0),  // width > height = horizontal
        ..default()
    },
    Slider::default(),
    SliderValue(50.0),
    SliderRange::new(0.0, 100.0),
    // ... thumb and track children
));
```

The orientation is automatically detected based on the node dimensions -
no API changes required!

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-12-09 05:16:59 +00:00
BD103 8c6e49018d Remove bevy_ptr::dangling_with_align() and inline it (#21822)
# Objective

- `bevy_ptr::dangling_with_align()` is only used once, in `bevy_ecs`'s
`BlobArray::with_capacity()`, and it isn't generally useful outside of
the engine's internals. We can remove the function and inline its
implementation into its call site.
- Additionally, `bevy_ptr::dangling_with_align()` has a TODO comment
that was leftover from
https://github.com/bevyengine/bevy/pull/15311#discussion_r1768091379,
where it was suggested that `dangling_with_align()` should use
`without_provenance()`.
- `with_addr()`, mentioned in the TODO comment, could also be used, but
it's a more roundabout solution. The reason it was mentioned was because
the original author thought it would be stabilized before
`without_provenance()`.

## Solution

- Remove `dangling_with_align()`.
- Replace its usage with `NonNull::without_provenance()` (since it is
now stable and doesn't require `unsafe` or pointer math)

## Testing

- I ran Miri with strict provenance checking enabled to ensure the
behavior is maintained.
  - `MIRIFLAGS="-Zmiri-strict-provenance" cargo +nightly miri test`

## But what is this provenance thingy?

[The official docs provide a more in-depth
explanation](https://doc.rust-lang.org/stable/std/ptr/index.html#provenance),
but basically a pointer is more than just a number referring to a memory
address. Pointers have _permissions_ associated with them that track:

- What set of memory addresses are allowed to be accessed
- When the pointer is allowed to access those addresses
- If the pointer is allowed to mutate the memory, or just read it

These permissions are pointer provenance. They aren't stored at runtime,
the Rust compiler doesn't know them at compile time! Miri is the only
tool that I know of that tracks provenance, which it uses to ensure
pointers adheres to their spatial, temporal, and mutability permissions.
That's why I mentioned Miri in the Testing section. :)
2025-12-09 05:10:18 +00:00
Chris Biscardi d6ae071771 anchor layout example (#21225)
# Objective

There was [some discussion in
discord](https://discord.com/channels/691052431525675048/1264881140007702558/1420909052879175810)
about "anchor layouts".

They are, as far as I can tell, basically absolute positioning.

## Solution

Write an example that shows how to "anchor" elements to the
top/left/right/bottom of a box. Also optionally included "centering"
using auto margins.

## Testing

```
cargo run --example anchor_positioning
```

Moving the window around changes the gray box sizes, while the interior
labels are "anchored" to their respective positions, offset from their
specific side attachments by 10 pixels

## Showcase

<img width="1562" height="888" alt="screenshot-2025-09-26-at-02 17
31@2x"
src="https://github.com/user-attachments/assets/c9af868b-c412-4292-802e-076d2c98ca6b"
/>

---------

Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
2025-12-08 11:55:03 +00:00
dependabot[bot] 9ad7df93c6 Update ron requirement from 0.11 to 0.12 (#22063)
Updates the requirements on [ron](https://github.com/ron-rs/ron) to
permit the latest version.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/ron-rs/ron/releases">ron's
releases</a>.</em></p>
<blockquote>
<h2>v0.12.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Add Serializer::into_inner method to extract the writer by <a
href="https://github.com/Thomas-Mewily"><code>@​Thomas-Mewily</code></a>
in <a
href="https://redirect.github.com/ron-rs/ron/pull/588">ron-rs/ron#588</a></li>
<li>Add <code>ron-lsp</code> to README by <a
href="https://github.com/jasonjmcghee"><code>@​jasonjmcghee</code></a>
in <a
href="https://redirect.github.com/ron-rs/ron/pull/589">ron-rs/ron#589</a></li>
<li>Fixed serde content detection for serde &gt;= 1.0.220 by <a
href="https://github.com/juntyr"><code>@​juntyr</code></a> in <a
href="https://redirect.github.com/ron-rs/ron/pull/582">ron-rs/ron#582</a></li>
<li>Further deprecate base64 byte strings by removing parsing support
outside the error path by <a
href="https://github.com/juntyr"><code>@​juntyr</code></a> in <a
href="https://redirect.github.com/ron-rs/ron/pull/566">ron-rs/ron#566</a></li>
<li>Bump ron to v0.12.0 by <a
href="https://github.com/juntyr"><code>@​juntyr</code></a> in <a
href="https://redirect.github.com/ron-rs/ron/pull/591">ron-rs/ron#591</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/Thomas-Mewily"><code>@​Thomas-Mewily</code></a>
made their first contribution in <a
href="https://redirect.github.com/ron-rs/ron/pull/588">ron-rs/ron#588</a></li>
<li><a
href="https://github.com/jasonjmcghee"><code>@​jasonjmcghee</code></a>
made their first contribution in <a
href="https://redirect.github.com/ron-rs/ron/pull/589">ron-rs/ron#589</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/ron-rs/ron/compare/v0.11.0...v0.12.0">https://github.com/ron-rs/ron/compare/v0.11.0...v0.12.0</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/ron-rs/ron/blob/master/CHANGELOG.md">ron's
changelog</a>.</em></p>
<blockquote>
<h2>[0.12.0] - 2025-11-12</h2>
<h3>API Changes</h3>
<ul>
<li>Breaking: Removed the <code>ron::error::Error::Base64Error</code>
variant. (<a
href="https://redirect.github.com/ron-rs/ron/pull/566">#566</a>)</li>
<li>Added <code>into_inner()</code> method to
<code>ron::ser::Serializer</code> to retrieve the inner writer. (<a
href="https://redirect.github.com/ron-rs/ron/pull/588">#588</a>)</li>
<li>Removed the <code>base64</code> dependency. (<a
href="https://redirect.github.com/ron-rs/ron/pull/566">#566</a>)</li>
</ul>
<h3>Format Changes</h3>
<ul>
<li><strong>Format-Breaking:</strong> Remote base64-encoded byte strings
deserialisation, replaced by Rusty byte strings in v0.9.0 (<a
href="https://redirect.github.com/ron-rs/ron/pull/566">#566</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>Fixed untagged enum deserialisation for serde &gt;= 1.0.220 with
better serde content detection (<a
href="https://redirect.github.com/ron-rs/ron/pull/582">#582</a>)</li>
</ul>
<h2>[0.11.0] - 2025-08-27</h2>
<h3>API Changes</h3>
<ul>
<li>Breaking: <code>SpannedError</code> now stores the full error span
in span: Span { start: Position, end: Position }`, to facilitate, e.g.,
language server highlighting of syntax errors.</li>
<li>Breaking: Added <code>no_std</code> support via a new
<code>std</code> feature (enabled by default). With default features
disabled, you must enable the <code>std</code> feature to access
<code>de::from_reader</code>, and the <code>std::io</code> operations on
<code>Options</code>, such as <code>from_reader</code>,
<code>from_reader_seed</code>, <code>to_io_writer</code>, and
<code>to_io_writer_pretty</code> (<a
href="https://redirect.github.com/ron-rs/ron/pull/567">#567</a>)</li>
<li>Breaking: Fixed (again) <code>ron::value::Number</code> to ensure it
is non-exhaustive, to avoid breaking <code>match</code>es when feature
unification enables more of its variants than expected (<a
href="https://redirect.github.com/ron-rs/ron/pull/568">#568</a>)</li>
</ul>
<h3>Examples</h3>
<ul>
<li>Add a new example <code>file_read_write_vec.rs</code> for reading
and writing <code>Vec&lt;T&gt;</code> to/from files. (<a
href="https://redirect.github.com/ron-rs/ron/pull/573">#573</a>)</li>
</ul>
<h2>[0.10.1] - 2025-04-08</h2>
<h3>API Changes</h3>
<ul>
<li>Add <code>ron::Options::to_io_writer</code> and
<code>ron::Options::to_io_writer_pretty</code> to allow writing into an
<code>io::Writer</code> (<a
href="https://redirect.github.com/ron-rs/ron/pull/561">#561</a>)</li>
<li>Breaking: <code>ron::value::Number</code> is now non-exhaustive, to
avoid breaking <code>match</code>es when feature unification enables
more of its variants than expected (<a
href="https://redirect.github.com/ron-rs/ron/pull/564">#564</a>)</li>
</ul>
<h2>[0.9.0] - 2025-03-18</h2>
<h3>API Changes</h3>
<ul>
<li>Add <code>ron::value::RawValue</code> helper type which can
(de)serialize any valid RON (<a
href="https://redirect.github.com/ron-rs/ron/pull/407">#407</a>)</li>
<li>Add <code>escape_strings</code> option to <code>PrettyConfig</code>
to allow serialising with or without escaping (<a
href="https://redirect.github.com/ron-rs/ron/pull/426">#426</a>)</li>
<li>Add <code>compact_maps</code> and <code>compact_structs</code>
options to <code>PrettyConfig</code> to allow serialising maps and
structs on a single line (<a
href="https://redirect.github.com/ron-rs/ron/pull/448">#448</a>)</li>
<li>Add minimal support for <code>#[serde(flatten)]</code> with
roundtripping through RON maps (<a
href="https://redirect.github.com/ron-rs/ron/pull/455">#455</a>)</li>
<li>Add minimal roundtripping support for <code>#[serde(tag =
&quot;tag&quot;)]</code>, <code>#[serde(tag = &quot;tag&quot;, content =
&quot;content&quot;)]</code>, and <code>#[serde(untagged)]</code> enums
(<a
href="https://redirect.github.com/ron-rs/ron/pull/451">#451</a>)</li>
<li>Breaking: Expand the <code>value::Number</code> enum to explicitly
encode all possible number types (<a
href="https://redirect.github.com/ron-rs/ron/pull/479">#479</a>)</li>
<li>Add <code>number_suffixes</code> option to <code>PrettyConfig</code>
to allow serialising numbers with their explicit type suffix, e.g.
<code>42i32</code> (<a
href="https://redirect.github.com/ron-rs/ron/pull/481">#481</a>)</li>
<li>Allow <code>ron::value::RawValue</code> to capture any whitespace to
the left and right of a ron value (<a
href="https://redirect.github.com/ron-rs/ron/pull/487">#487</a>)</li>
<li>Breaking: Enforce that ron always writes valid UTF-8 (<a
href="https://redirect.github.com/ron-rs/ron/pull/488">#488</a>)</li>
<li>Add convenient <code>Value::from</code> impls (<a
href="https://redirect.github.com/ron-rs/ron/pull/498">#498</a>)</li>
<li>Add new extension <code>explicit_struct_names</code> which requires
that struct names are included during deserialization (<a
href="https://redirect.github.com/ron-rs/ron/pull/522">#522</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/ron-rs/ron/commit/c6a8cff1eff986cc1ad9b026e838335187d411f0"><code>c6a8cff</code></a>
Bump ron to v0.12.0 (<a
href="https://redirect.github.com/ron-rs/ron/issues/591">#591</a>)</li>
<li><a
href="https://github.com/ron-rs/ron/commit/f2c17284b4df666437614db57f5334c963dba201"><code>f2c1728</code></a>
v0.12: Further deprecate base64 byte strings by removing parsing support
outs...</li>
<li><a
href="https://github.com/ron-rs/ron/commit/5630b0f1843b2e3cb1c856961dfc941326bd225e"><code>5630b0f</code></a>
Fixed serde content detection for serde &gt;= 1.0.220 (<a
href="https://redirect.github.com/ron-rs/ron/issues/582">#582</a>)</li>
<li><a
href="https://github.com/ron-rs/ron/commit/3184df3d2c778cba512bcb3ae9ee4109ca7c01ea"><code>3184df3</code></a>
Add <code>ron-lsp</code> to README (<a
href="https://redirect.github.com/ron-rs/ron/issues/589">#589</a>)</li>
<li><a
href="https://github.com/ron-rs/ron/commit/9b9b88e70d64e24805fd7824192348d695480ee7"><code>9b9b88e</code></a>
Add Serializer::into_inner method to extract the writer (<a
href="https://redirect.github.com/ron-rs/ron/issues/588">#588</a>)</li>
<li>See full diff in <a
href="https://github.com/ron-rs/ron/compare/v0.11.0...v0.12.0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-08 07:37:45 +00:00
Daniel Skates f9d59f8206 Fix cargo features lint (#22008)
# Objective

`markdownlint` fails on `docs/cargo_features.md` as it doesn't like the
space before the pipe at the end of this line

## Solution

- Add a `.`

## Testing

- CI
2025-12-02 17:03:54 +00:00
ickshonpe 0d46518eb2 Remove viewport_debug from web examples (#21804)
# Objective

Fixes #21803

## Solution

Set `wasm = false` for the example.
2025-11-13 23:43:37 +00:00
François Mockers 5f7994eea8 do not require bevy_dev_tools for states example (#19364)
# Objective

- Example `states` require the `bevy_dev_tools` feature even though its
not needed for states

## Solution

- Make the `bevy_dev_tools` feature optional, and explain why it can be
used
2025-11-13 23:39:11 +00:00
Joe Buehler 0c90f047b4 Add Automatic Directional Navigation Graph Generation (#21668)
## Objective

Resolves #21661 

Adds automatic directional navigation graph generation based on UI node
positions and sizes, eliminating the need for tedious manual graph
construction in dynamic UIs.

## Solution

Implements a spatial navigation algorithm that automatically computes
the nearest neighbor in each compass direction for UI elements, while
respecting any manually-defined edges.

### Features

- **Automatic edge generation**: Finds the best neighbor in each of 8
compass directions based on distance, alignment, and overlap
- **Manual override support**: Manual edges always take precedence over
auto-generated ones
- **Configurable**: `AutoNavigationConfig` resource allows tuning
alignment requirements, distance limits, and preference weighting
- **Opt-in**: Entities must have `AutoDirectionalNavigation` component
added to use, and therefore **not** a breaking change
- **Generic**: Core algorithm works with any `Vec2` position/size data,
not just `bevy_ui`

### Implementation

**New Components & Resources**
(`bevy_input_focus/src/directional_navigation.rs`):
- `AutoDirectionalNavigation` - Marker component to enable
auto-navigation
- `AutoNavigationConfig` - Configuration resource with settings:
- `min_alignment_factor`: Minimum perpendicular overlap (0.0-1.0)
required for cardinal directions
  - `max_search_distance`: Optional distance limit for connections
  - `prefer_aligned`: Whether to strongly prefer well-aligned nodes

**Core Algorithm**:
```rust
pub fn auto_generate_navigation_edges(
    nav_map: &mut DirectionalNavigationMap,
    nodes: &[(Entity, Vec2, Vec2)],  // (entity, center_pos, size)
    config: &AutoNavigationConfig,
)
```

For each node and each direction:
1. Filter candidates that are actually in that direction (cone-based
check)
2. Calculate overlap factor for cardinal directions (horizontal overlap
for N/S, vertical for E/W)
3. Score candidates based on:
   - Distance (closer is better)
   - Alignment with direction vector (more aligned is better)
   - Overlap factor (must meet minimum threshold)
4. Select the best-scoring candidate as the neighbor

**Scoring Formula**:
```
score = distance + alignment_penalty
where alignment_penalty = (1.0 - alignment) * distance * 2.0
```

This makes misaligned nodes significantly less attractive while still
considering distance.

### Usage

**Before (manual)**:
```rust
// Must manually specify all connections
for row in 0..N_ROWS {
    let entities_in_row: Vec<Entity> = (0..N_COLS)
        .map(|col| button_entities.get(&(row, col)).unwrap())
        .copied()
        .collect();
    directional_nav_map.add_looping_edges(&entities_in_row, CompassOctant::East);
}

// Repeat for columns...
for col in 0..N_COLS {
    let entities_in_column: Vec<Entity> = (0..N_ROWS)
        .map(|row| button_entities.get(&(row, col)).unwrap())
        .copied()
        .collect();
    directional_nav_map.add_edges(&entities_in_column, CompassOctant::South);
}
```

**After**:
```rust
// Just add the `AutoDirectionalNavigation` component!
commands.spawn((
    Button,
    Node { /* ... */ },
    AutoDirectionalNavigation::default(),
    // ... other components
));
```

## Testing
- Added new example: `auto_directional_navigation`
- Ran existing `directional_navigation`

## Showcase

### New Example: `auto_directional_navigation`

Demonstrates automatic navigation with irregularly-positioned buttons.
Unlike a regular grid, these buttons are scattered, but auto-navigation
figures out the correct connections - also shows currently focused
button, and the last "input" pressed to show the logical flow of
navigating:

```bash
cargo run --example auto_directional_navigation
```



https://github.com/user-attachments/assets/8dce1d8d-53b5-41b8-bc9a-7e32067f7978




**Key differences from manual `directional_navigation` example**:
- No manual `add_edges()` or `add_looping_edges()` calls
- Buttons positioned irregularly (not in a perfect grid)
- Works with absolute positioning and dynamic layouts

## Migration Guide

No breaking changes - this is a purely additive feature.

To adopt automatic navigation:
1. Add `AutoDirectionalNavigation` component to focusable entities
2. Optionally configure `AutoNavigationConfig` resource
2025-11-10 03:54:01 +00:00
IceSentry e49910484d Move manual_material to shader_advanced category (#21735)
# Objective

- This example is intended for advanced users

## Solution

- Move it to the shader_advanced category

## Testing

- I ran the example and it worked
2025-11-03 18:53:24 +00:00
ickshonpe 8d1bf6ec5e Rename the strikethrough example to strikethrough_and_underline (#21689)
# Objective

Rename the example, fix a typo in its ("it's") comments.
2025-10-29 21:05:33 +00:00
syszery 1bd6f42719 Fix(examples): improve async examples to showcase good patterns (#21647)
# Objective

In #21598 and the related Discord discussion, it was pointed out that
the `async_compute` example promotes an inefficient and potentially
error-prone pattern: `future::block_on(poll_once)`.

It is now recommended to use `bevy::tasks::futures::check_ready`
instead, which is much cheaper and avoids blocking the main thread while
waiting on the future. Another valid approach is to pass a channel into
the async tasks and detach them, letting the channel handle task
readiness.

This PR implements both suggestions.


## Solution

* **Updated `async_compute` example**
Replaced the use of `future::block_on(poll_once)` with the recommended
`check_ready`.
  The change is minimal and limited to the directly affected lines.

* **Added new example: `async_channel_pattern`**
Demonstrates how to spawn async tasks using a channel-based
communication pattern.

* Each task is executed on a separate thread via `AsyncComputeTaskPool`.
* Results (cube positions) are sent back through a `CubeChannel` once
completed.
* Tasks are detached to run fully asynchronously, ensuring the main
thread remains unblocked.
* A rotating light in the scene visually indicates that the frame loop
remains responsive.



I am relatively new to both Bevy and async Rust, and I genuinely
appreciate any feedback or suggestions to improve these examples —
especially regarding idiomatic async patterns and best practices for
Bevy task management.

Fixes #21598

---------

Co-authored-by: syszery <syszery@users.noreply.github.com>
Co-authored-by: François Mockers <francois.mockers@vleue.com>
2025-10-28 22:35:21 +00:00
ickshonpe 160661b944 Text strikethrough (#21555)
# Objective

Add minimal strikethrough support for text.

## Solution

* Insert the new `Strikethrough` component on any `Text`, `Text2d`, or
`TextSpan` entity and its text will be drawn with strikethrough.
* The strikethrough geometry is stored in `TextLayoutInfo` in the vec
with the section bounding rects.
* Rendering is trivial, identical to drawing text background colours
except it's a narrower rect drawn in front instead of behind.
* Text shadows also have strikethrough if the text does.

#

This implementation can easily be expanded to support underline, I've
already made a follow up PR that does this here: #21559.

## Testing

```
cargo run --example strikethrough
```

## Showcase

<img width="1422" height="924" alt="strikeout"
src="https://github.com/user-attachments/assets/c8ea2578-e40c-4c46-ae0d-df9e3f261f3a"
/>
2025-10-21 23:14:32 +00:00
syszery 9a9817bba1 Update PanCam and FreeCam to use full term Camera (#21592)
# Objective

This PR fixes #21569, which proposes renaming the newly introduced
camera controller modules `FreeCam` and `PanCam` to use the full term
`Camera`.

## Solution

* Renamed the `PanCam` controller, `PanCamPlugin`, and related methods
to use the full term `Camera` instead of the abbreviation `Cam`.
* Renamed the module from `pan_cam` to `pan_camera` for consistency with
naming conventions.
* Updated the example `pan_camera_controller` and adjusted usage of the
renamed controller and plugin.
* Updated documentation and release notes accordingly.


## Follow-up Work

I see two options from here:

1. **Use this PR as a reference** for renaming `FreeCam`. The process is
similar and could be a great first issue for someone looking to
contribute to the new camera modules or Bevy in general. Most of the
changes follow the same pattern, although `FreeCam` has more examples
that need updating. One could find them using `grep` (e.g., `grep
FreeCam`) or by reviewing the diff from the PR that introduced
`FreeCam`: #20215

2. **I can continue and update this PR** to also handle the `FreeCam`
renaming, if you'd prefer to resolve the entire issue in one go.

---------

Co-authored-by: syszery <syszery@users.noreply.github.com>
2025-10-20 21:49:37 +00:00
WaterWhisperer a48d6cd336 Rename bevy_reflect's documentation feature to reflect_documentation (#21577)
# Objective

Fixes #14309 

## Solution

Renamed the `bevy_reflect` feature from `documentation` to
`reflect_documentation` to follow the naming convention where features
are prefixed with their module name.

## Changes

- Renamed feature `documentation` to `reflect_documentation` in:
  - `bevy_reflect/Cargo.toml`
  - `bevy_reflect/derive/Cargo.toml`
  - `bevy_internal/Cargo.toml`
- Updated all conditional compilation attributes from `#[cfg(feature =
"documentation")]` to `#[cfg(feature = "reflect_documentation")]`
- Updated example documentation in `reflect_docs.rs`

## Testing

<img width="1414" height="688" alt="截图 2025-10-17 18-52-14"
src="https://github.com/user-attachments/assets/461d827a-c958-4c0d-862d-aae25598f2f7"
/>
2025-10-19 17:30:19 +00:00
syszery 81d9c88950 feat(pan-cam): add scaffolding for 2D pan camera controller (#21520)
# Objective

Implements scaffolding for a 2D pan camera controller.

Fixes #21468 


## Solution

- Introduced a `PanCam` component with settings for panning, zooming,
and rotation via keyboard input, following the design of the existing
`FreeCam`.
- Added a `PanCamPlugin` to register the controller system.
- Implemented keyboard-based panning and rotation.


## TODOs

- Movement is currently world-axis aligned. 
  - TODO: Consider movement relative to camera rotation.
- Zooming support is scaffolded with config fields but not yet
implemented.


## Testing

Unfortunately, I was unable to fully test this implementation due to
issues running graphical output with GPU acceleration under WSL.
As a result, zoom behavior and rotation effects remain TODOs, and the
whole code could not be fully verified.

Once I resolve the GPU passthrough issues, I plan to complete and test
the remaining features (with a more meaningful example).

---

I'm happy to hear any suggestions or feedback in the meantime!

---------

Co-authored-by: syszery <syszery@users.noreply.github.com>
Co-authored-by: Janis <130913856+janis-bhm@users.noreply.github.com>
2025-10-16 21:32:24 +00:00
atlv b81dabe433 bevy_gizmos_render (#21536)
# Objective

- make gizmos render agnostic

## Solution

- split crate

## Testing

- ci and a few examples

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: François Mockers <francois.mockers@vleue.com>
2025-10-14 21:36:36 +00:00
Carter Anderson f3ec3c070e Cargo Feature Collections (#21472)
## Objective

Users of the `bevy` crate currently live one of two lifestyles:

1. Use all of Bevy's default features, potentially compiling many
features you don't need or don't want. If there is a feature you _cannot
have_ in your app, you must move on to option (2)
2. Disable Bevy's default features, and compose the complete list of
features yourself.

Living in the world of (2) is an exercise in frustration, as the list of
required features to accomplish a given task changes regularly across
releases as we add and change features. This is an _expert level_ task
that requires intimate knowledge of engine internals to get right. Even
I, Bevy's lead developer, would struggle here. To the point that I would
never voluntarily choose to disable Bevy's default features.

Most games/apps are 2D-only, 3D-only, or UI-only and don't require the
full set of features. We cannot currently in good conscience recommend
that those developers live in the "no default features" world. That is a
fast track to pain, suffering, and perhaps a quick exit from the Bevy
ecosystem.

The same problem exists for developers that want to build their own Bevy
renderer or replace Bevy UI with their own framework. Once again, we
_cannot_ recommend that those developers manage every Bevy feature
themselves.

Fixes: #21369
Alternative to: #20741 #21236

## Solution

Define a "standalone" set of features that enable Bevy developers to
disable default features, then opt in to the funtionality they want. The
"default" `bevy` feature set is now just:

```toml
default = ["2d", "3d", "ui"]
```

This enables developers to select only the features they need. For
example, a UI-only app would look like this:

```toml
bevy = { version = "0.17", default-features = false, features = [ "ui" ] }
```

"2d", "3d", and "ui" each contain the "full" Bevy experience for that
domain. This also includes:
- `default_platform`: the default "platform support" features (see docs)
- `default_app`: the default "app framework" features (see docs)

For developers that do not want the default bevy render / platform / app
functionality, this breaks down further into:

- `common_api`: common / core backend-less user-facing Bevy render api
- `2d_api`: common / core backend-less user-facing Bevy 2d api
- `3d_api`: common / core backend-less user-facing Bevy 3d api
- `ui_api`: common / core backend-less user-facing Bevy ui api

(and many others)

I've also added the `dev` feature to this PR, which enables the
recommended "dev only" features like dynamic linking, asset watching /
hot reloading, and dev / debug tools. Including dynamic linking is a bit
controversial here given that it doesn't work everywhere. But I'd like
to aggressively push people into the dynamic linking workflow wherever
possible, as developing without it is signficantly worse. And removing a
single `dev` feature is a much simpler release workflow.

---------

Co-authored-by: atlv <email@atlasdostal.com>
2025-10-10 02:42:54 +00:00
Niyudi 7376755266 Freecam example (#21477)
# Objective

Addresses #21467.

## Solution

Adds the "free_cam_controller" example, that contains a simple scene
with a camera controlled by the FreeCamPlugin. the code explains how to
change the settings in the FreeCam component and the example provides
bindings to change sensitivity and friction live.

## Testing

`cargo run --example free_cam_controller --features="free_cam"`

As this is my first contribution to the project, please let me know
about any problems.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-10-09 19:37:02 +00:00
Alice Cecile abdf657eff Fix feature flags for solari and meshlets examples (#21474)
# Objective

The `solari` example does not compile when run with the
required-features following #20215.

## Solution

Require the new free_cam feature.

## Testing

`cargo build --example solari --features="bevy_solari https free_cam"`
2025-10-09 04:39:17 +00:00
François Mockers 5316053aed un-hide the feathers example (#21463)
# Objective

- Example feathers is hidden, maybe because its experimental
- Other examples are using the experimental feathers feature and are not
hidden

## Solution

- un hide the feathers example

I would like this to be part of the next 0.17 patch, feathers is part of
the release notes, it's a bit sad to not be able to show the example on
the website
2025-10-09 03:00:16 +00:00
atlv 44b904ed05 Rename bevy_mesh_picking_backend to mesh_picking (#21436)
# Objective

- Only prefix features bevy_ if they correspond to a crate
- Another step towards #20867

## Solution

- rename it

## Testing

- ci
2025-10-07 23:49:49 +00:00
Alice Cecile 66e8232412 Add bevy_camera_controllers crate and move freecam implementation into it (#20215)
# Objective

Moving the camera around is really important to validate that our scenes
are rendered correctly.

Bevy engine devs currently do this via a fairly cursed "library example"
which includes a basic freecam controller (which is technically distinct
from a flycam apparently). This has three problems:

1. Oh god why are we taking pseudo-dependencies on other examples.
2. Something like this would be useful for debugging for users.
3. Something like this would be useful for the editor and other tooling.

## Solution

Create a new `bevy_camera_controllers` crate, and move the existing
freecam implementation into it, nearly verbatim.

This cleans up some ugly tech debt in how we do this, makes it easier to
add a camera controller to other examples, and also gives us a scaffold
for future camera controllers.

This PR has been marked `X-Blessed`, as I went over this plan with @cart
in a [meeting on
2025-06-23](https://discord.com/channels/691052431525675048/692572690833473578/1386847828923519038),
and we both agreed that this was the right first step.

## Testing

I've tested the examples that rely on this camera controller: they work
just like before.

## Notes for reviewers

- I don't intend to land this in Bevy 0.17: the existing example code is
not high enough quality for me to be happy shipping this
- we're also soft feature-frozen; I was just in the mood to do this
today
- this PR has some minimal cleanup: just enough naming and docs work to
make this code not an active liability. Any more will risk derailing
this PR and making it harder to review
- I've opted to expose top-level feature flags for the various camera
controllers. This is a bit noisy, but it was the only sensible way I
could see to both have "no camera controllers by default" and "still
easy to use these controllers in examples"
- this will not be the only camera controller in this crate, or the Bevy
Editor
- this is not the place to discuss "what should the default camera
controller for the Bevy Editor be"
- if you think this crate, or this particular move is the wrong strategy
for some other reason though, please do speak up :)
- my personal (unblessed) hope is that we continue to add camera
controllers to this crate as needed for various first-party tooling. I
will probably largely push-back on adding camera controllers that we do
not actively use to this crate, since I don't think they make great
libraries in general (much better to copy-paste)

## TODO

- [x] add release note. I'm waiting until after Bevy 0.17 ships to do
this
- [x] update the examples/README.md file. I was lazy and didn't want to
constantly resolve merge conflicts on that while this PR sits
- [x] change to singular crate name

## Future work

- split apart the giant camera controller component
- make keybinding better, either with or without a real input manager
solution
- split apart the system to make it more modular
- make the system handle fixed timesteps better
- use the camera controller in more examples for debugging
- add more camera controllers!

---------

Co-authored-by: atlv <email@atlasdostal.com>
Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
2025-10-07 19:39:17 +00:00
atlv 14756e100c Rename bevy_ui_picking_backend to ui_picking (#21435)
# Objective

- Only prefix features bevy_ if they correspond to a crate
- Another step towards #20867

## Solution

- rename it

## Testing

- ci
2025-10-07 19:06:20 +00:00
atlv 9fe6234b8e rename bevy_sprite_picking_backend to sprite_picking (#21437)
# Objective

- Only prefix features bevy_ if they correspond to a crate
- Another step towards #20867

## Solution

- rename it

## Testing

- ci
2025-10-07 16:20:28 +00:00
atlv 40df90cf73 Make bevy_mikktspace optional (#21390)
# Objective

- allow users to cut unneeded deps

## Solution

- feature gate

## Testing

- clearcoat example uses generated tangents, still works.
2025-10-06 22:05:51 +00:00
atlv b7a90ae653 make bevy_mesh optional for bevy_animate (#20742)
# Objective

- make bevy_mesh optional for bevy_animate as mentioned in
https://github.com/bevyengine/bevy/pull/20714#issuecomment-3218581329

## Solution

- copy paste the morph weights stuff out into a module, gate it, then
add the optional dep
2025-10-06 21:04:14 +00:00
atlv ff7837ef38 Rename animation to gltf_animation (#21388)
# Objective

- Step towards #20867

## Solution

- Do a rename

## Testing

- Ran some examples
2025-10-06 20:54:26 +00:00
atlv c23377228c bevy_mesh optional morph (#21389)
# Objective

- make morph support optional on bevy_mesh
- unblock #20742
- another step towards #20867

## Solution

- feature

## Testing

- morph targets example works
2025-10-06 18:53:27 +00:00
dependabot[bot] 1e2324980b Update ron requirement from 0.10 to 0.11 (#21416)
Updates the requirements on [ron](https://github.com/ron-rs/ron) to
permit the latest version.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/ron-rs/ron/releases">ron's
releases</a>.</em></p>
<blockquote>
<h2>v0.11.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Add <code>no_std</code> Support by <a
href="https://github.com/bushrat011899"><code>@​bushrat011899</code></a>
in <a
href="https://redirect.github.com/ron-rs/ron/pull/567">ron-rs/ron#567</a></li>
<li>SpannedError: Store error span by <a
href="https://github.com/pfnsec"><code>@​pfnsec</code></a> in <a
href="https://redirect.github.com/ron-rs/ron/pull/569">ron-rs/ron#569</a></li>
<li>Fix (again) non-exhaustive matching on Number by <a
href="https://github.com/juntyr"><code>@​juntyr</code></a> in <a
href="https://redirect.github.com/ron-rs/ron/pull/568">ron-rs/ron#568</a></li>
<li>Add file IO with Vec<!-- raw HTML omitted --> example by <a
href="https://github.com/LanHikari22"><code>@​LanHikari22</code></a> in
<a
href="https://redirect.github.com/ron-rs/ron/pull/573">ron-rs/ron#573</a></li>
<li>Patch serde content detection hack by <a
href="https://github.com/juntyr"><code>@​juntyr</code></a> in <a
href="https://redirect.github.com/ron-rs/ron/pull/580">ron-rs/ron#580</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/bushrat011899"><code>@​bushrat011899</code></a>
made their first contribution in <a
href="https://redirect.github.com/ron-rs/ron/pull/567">ron-rs/ron#567</a></li>
<li><a href="https://github.com/pfnsec"><code>@​pfnsec</code></a> made
their first contribution in <a
href="https://redirect.github.com/ron-rs/ron/pull/569">ron-rs/ron#569</a></li>
<li><a
href="https://github.com/LanHikari22"><code>@​LanHikari22</code></a>
made their first contribution in <a
href="https://redirect.github.com/ron-rs/ron/pull/573">ron-rs/ron#573</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/ron-rs/ron/compare/v0.10.1...v0.11.0">https://github.com/ron-rs/ron/compare/v0.10.1...v0.11.0</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/ron-rs/ron/blob/master/CHANGELOG.md">ron's
changelog</a>.</em></p>
<blockquote>
<h2>[0.11.0] - 2025-08-27</h2>
<h3>API Changes</h3>
<ul>
<li>
<p>Breaking: <code>SpannedError</code> now stores the full error span in
span: Span { start: Position, end: Position }`, to facilitate, e.g.,
language server highlighting of syntax errors.</p>
</li>
<li>
<p>Breaking: Added <code>no_std</code> support via a new
<code>std</code> feature (enabled by default). With default features
disabled, you must enable the <code>std</code> feature to access
<code>de::from_reader</code>, and the <code>std::io</code> operations on
<code>Options</code>, such as <code>from_reader</code>,
<code>from_reader_seed</code>, <code>to_io_writer</code>, and
<code>to_io_writer_pretty</code> (<a
href="https://redirect.github.com/ron-rs/ron/pull/567">#567</a>)</p>
</li>
<li>
<p>Breaking: Fixed (again) <code>ron::value::Number</code> to ensure it
is non-exhaustive, to avoid breaking <code>match</code>es when feature
unification enables more of its variants than expected (<a
href="https://redirect.github.com/ron-rs/ron/pull/568">#568</a>)</p>
</li>
</ul>
<h3>Examples</h3>
<ul>
<li>Add a new example <code>file_read_write_vec.rs</code> for reading
and writing <code>Vec&lt;T&gt;</code> to/from files. (<a
href="https://redirect.github.com/ron-rs/ron/pull/573">#573</a>)</li>
</ul>
<h2>[0.10.1] - 2025-04-08</h2>
<h3>API Changes</h3>
<ul>
<li>Add <code>ron::Options::to_io_writer</code> and
<code>ron::Options::to_io_writer_pretty</code> to allow writing into an
<code>io::Writer</code> (<a
href="https://redirect.github.com/ron-rs/ron/pull/561">#561</a>)</li>
<li>Breaking: <code>ron::value::Number</code> is now non-exhaustive, to
avoid breaking <code>match</code>es when feature unification enables
more of its variants than expected (<a
href="https://redirect.github.com/ron-rs/ron/pull/564">#564</a>)</li>
</ul>
<h2>[0.9.0] - 2025-03-18</h2>
<h3>API Changes</h3>
<ul>
<li>Add <code>ron::value::RawValue</code> helper type which can
(de)serialize any valid RON (<a
href="https://redirect.github.com/ron-rs/ron/pull/407">#407</a>)</li>
<li>Add <code>escape_strings</code> option to <code>PrettyConfig</code>
to allow serialising with or without escaping (<a
href="https://redirect.github.com/ron-rs/ron/pull/426">#426</a>)</li>
<li>Add <code>compact_maps</code> and <code>compact_structs</code>
options to <code>PrettyConfig</code> to allow serialising maps and
structs on a single line (<a
href="https://redirect.github.com/ron-rs/ron/pull/448">#448</a>)</li>
<li>Add minimal support for <code>#[serde(flatten)]</code> with
roundtripping through RON maps (<a
href="https://redirect.github.com/ron-rs/ron/pull/455">#455</a>)</li>
<li>Add minimal roundtripping support for <code>#[serde(tag =
&quot;tag&quot;)]</code>, <code>#[serde(tag = &quot;tag&quot;, content =
&quot;content&quot;)]</code>, and <code>#[serde(untagged)]</code> enums
(<a
href="https://redirect.github.com/ron-rs/ron/pull/451">#451</a>)</li>
<li>Breaking: Expand the <code>value::Number</code> enum to explicitly
encode all possible number types (<a
href="https://redirect.github.com/ron-rs/ron/pull/479">#479</a>)</li>
<li>Add <code>number_suffixes</code> option to <code>PrettyConfig</code>
to allow serialising numbers with their explicit type suffix, e.g.
<code>42i32</code> (<a
href="https://redirect.github.com/ron-rs/ron/pull/481">#481</a>)</li>
<li>Allow <code>ron::value::RawValue</code> to capture any whitespace to
the left and right of a ron value (<a
href="https://redirect.github.com/ron-rs/ron/pull/487">#487</a>)</li>
<li>Breaking: Enforce that ron always writes valid UTF-8 (<a
href="https://redirect.github.com/ron-rs/ron/pull/488">#488</a>)</li>
<li>Add convenient <code>Value::from</code> impls (<a
href="https://redirect.github.com/ron-rs/ron/pull/498">#498</a>)</li>
<li>Add new extension <code>explicit_struct_names</code> which requires
that struct names are included during deserialization (<a
href="https://redirect.github.com/ron-rs/ron/pull/522">#522</a>)</li>
<li>Add new path-based field metadata serialization support via
<code>PrettyConfig</code> (<a
href="https://redirect.github.com/ron-rs/ron/pull/544">#544</a>)</li>
<li>Breaking: Change <code>PrettyConfig</code> so that
<code>new_line</code>, <code>indentor</code> and <code>separator</code>
are all <code>Cow&lt;'static, str&gt;</code> instead of
<code>String</code> (<a
href="https://redirect.github.com/ron-rs/ron/pull/546">#546</a>)</li>
</ul>
<h3>Format Changes</h3>
<ul>
<li>[Non-API] Breaking: Treat <code>Some</code> like a newtype variant
with <code>unwrap_variant_newtypes</code> (<a
href="https://redirect.github.com/ron-rs/ron/pull/465">#465</a>)</li>
<li>Allow parsing floating point literals with underscores (<a
href="https://redirect.github.com/ron-rs/ron/pull/481">#481</a>)</li>
<li><strong>Format-Breaking:</strong> Switch from base64-encoded to
Rusty byte strings, still allow base64 deserialising for now (<a
href="https://redirect.github.com/ron-rs/ron/pull/438">#438</a>)</li>
<li>Fix issue <a
href="https://redirect.github.com/ron-rs/ron/issues/241">#241</a> and
allow parsing numbers with explicit type suffixes, e.g. <code>1u8</code>
or <code>-1f32</code> (<a
href="https://redirect.github.com/ron-rs/ron/pull/481">#481</a>)</li>
<li>Add support for byte literals as strongly typed unsigned 8-bit
integers (<a
href="https://redirect.github.com/ron-rs/ron/pull/438">#438</a>)</li>
<li>Fix issue <a
href="https://redirect.github.com/ron-rs/ron/issues/321">#321</a> and
allow parsing UTF-8 identifiers (<a
href="https://redirect.github.com/ron-rs/ron/pull/488">#488</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/ron-rs/ron/commit/cdd9fccd76e4c2f515706453f7c0e4351b8f3784"><code>cdd9fcc</code></a>
Bump ron to v0.11.0</li>
<li><a
href="https://github.com/ron-rs/ron/commit/1dcc70e5d759b48ee1b861757fc4f52facec2b0d"><code>1dcc70e</code></a>
Patch serde content detection hack (<a
href="https://redirect.github.com/ron-rs/ron/issues/580">#580</a>)</li>
<li><a
href="https://github.com/ron-rs/ron/commit/29e244a21cc8eefeceb6a3a7e2be71760a0ce792"><code>29e244a</code></a>
Add file IO with Vec&lt;T&gt; example (<a
href="https://redirect.github.com/ron-rs/ron/issues/573">#573</a>)</li>
<li><a
href="https://github.com/ron-rs/ron/commit/ba572011ad8eb24992cb6fa9e540a86e3e249a91"><code>ba57201</code></a>
Fix (again) non-exhaustive matching on Number (<a
href="https://redirect.github.com/ron-rs/ron/issues/568">#568</a>)</li>
<li><a
href="https://github.com/ron-rs/ron/commit/27a26d691a24ac1eef3462086eed31dcbc0196f9"><code>27a26d6</code></a>
SpannedError: Store error span (<a
href="https://redirect.github.com/ron-rs/ron/issues/569">#569</a>)</li>
<li><a
href="https://github.com/ron-rs/ron/commit/b7a5bfcef32ac68d7aff4d9984c30fa83f159305"><code>b7a5bfc</code></a>
Add <code>no_std</code> support (<a
href="https://redirect.github.com/ron-rs/ron/issues/567">#567</a>)</li>
<li><a
href="https://github.com/ron-rs/ron/commit/3159534d8111a31d33791826aef2132308cc032c"><code>3159534</code></a>
Add 564_exhaustive_number test</li>
<li>See full diff in <a
href="https://github.com/ron-rs/ron/compare/v0.10.1...v0.11.0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-06 07:12:57 +00:00
Jan Hohenheim eac8bc7cc4 Exclude ICEing example from doc scrape (#21308) 2025-10-01 00:10:54 +00:00
James Liu ca506d73ce Bump crate versions to 0.18.0-dev (#21001)
# Objective
The 0.17 release candidate process has been started. We should be able
to start merging PRs scheduled for 0.18 now.

## Solution
Update the crate versions all to `0.18.0-dev`
2025-09-22 16:53:58 +00:00
Chris Biscardi 6da51ef236 move gltf examples to gltf category (#21141)
# Objective

In the context of this PR, there are two access patterns users have when
reaching for examples:

- "I have a glTF file and I need to figure out what to do with it"
- "I want to learn about Bevy feature X"

Users wanting to learn about Bevy features can go to any appropriately
named examples directory to learn more about that feature.
Users who have a glTF file currently have to scan different directories
to find glTF related functionality.
For example: looking in the 2d directory for custom vertex attribute
examples.

## Solution

Create a glTF category and move applicable examples there.

It is notable that a "gltf" directory *could* accept any example that
uses a glTF file, but this should not be the case.
The examples in this directory should be focused on the "I have a glTF
file and I'm trying to figure out how to work with it" access pattern.

If a glTF file is used "as data" to support a feature showcase, then it
is not "a gltf example". For example: spawning a Scene from a glTF file
is not enough to qualify an example for this directory.

I chose to call this directory "gltf" instead of using the "scene"
directory so as to leave "scene" for bsn examples in the future.

## Testing

```
cargo run --example custom_gltf_vertex_attribute
cargo run --example load_gltf
cargo run --example load_gltf_extras
cargo run --example query_gltf_primitives
cargo run --example update_gltf_scene
cargo run --example edit_material_on_gltf
cargo run --example gltf_skinned_mesh
```
2025-09-21 16:43:18 +00:00
Alice Cecile d38a1ec982 Mark bevy_ui_widgets as experimental for now (#20972)
# Objective

- These are still going to undergo *extensive* change: users should be
aware of what they're getting into.
- Fixes #20957.

## Solution

- [x] rename the feature
- [x] remove from our default features
- [x] add warning to crate docs
- [x] add warning to release notes
- [x] add warnings to examples

## Testing

I've run both the `standard_widgets` and `standard_widgets_observers`
examples succesfully.
2025-09-12 16:03:03 +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
Chris Biscardi d3f9699e68 add reflection serialization example (#20940)
# Objective

It is a very common[0] misconception that serde's Serialize/Deserialize
derives are required for reflection (de)serialization. This is not true,
and can lead to unexpectedly changing the serialization behavior in a
way that doesn't get exposed via reflection information. Having an
example to point to would be a useful resource when talking about this.

[0]: This is why Avian has Serialize/Deserialize on all types, including
marker types; This also cropped up in PRs to new BRP functionality.

## Solution

Implement an example showing deserialization and serialization for a
type that only implements `Reflect`, and not serde's `Serialize` or
`Deserialize`.

## Testing

```
cargo run --example serialization
2025-09-09T19:08:28.258523Z  INFO serialization: reflect_value=DynamicStruct(serialization::Player { health: 50, name: "BevyPlayerOne" })
2025-09-09T19:08:28.258770Z  INFO serialization: player=serialization::Player { name: "BevyPlayerOne", health: 50 }
2025-09-09T19:08:28.259382Z  INFO serialization: json="{\"serialization::Player\":{\"name\":\"BevyPlayerSerialize\",\"health\":80}}"
```
2025-09-09 22:25:45 +00:00
atlv eed2e0ebe6 Fix missed RedrawRequested and WindowCloseRequested events with UpdateMode::Reactive (part 2) [ADOPTED] (#20624)
# Objective

- Adopt and rebase #18549

## Solution

- merge conflicts were just if let chains

## Testing

- example added by the PR works on mac

---------

Co-authored-by: Matt Thompson <matt@boondocker.io>
Co-authored-by: Aaron Loucks <aloucks@cofront.net>
Co-authored-by: François Mockers <francois.mockers@vleue.com>
2025-09-07 07:51:02 +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
atlv ac380673b7 rename bevy_anti_aliasing to bevy_anti_alias (#20857)
# Objective

- rename to have less suffixing
- match future bevy_post_process crate

## Solution

- remove ing

## Testing

- run anti_aliasing example (not renamed, can rename this too if
desired)
2025-09-04 21:11:20 +00:00
Patrick Walton 89f9dcb431 Don't require cameras to have color render targets. (#20830)
It can occasionally be useful to have cameras that *only* render
prepasses such as depth. Other game engines such as Unity support this
feature by allowing a depth-only render target to be assigned to a
camera. Bevy, however, has no easy mechanism for this. (Creating an
`ShadowView` in the render app doesn't work, because various places in
rendering assume that shadow views are associated with lights.)

This patch fixes the problem by introducing a new type of
`RenderTarget`, `RenderTarget::None`. Cameras with no render target will
skip the main opaque and transparent render passes, but any prepasses on
such cameras will still occur. Adding a `DepthPrepass` to such a camera
enables depth-only cameras, with maximum efficiency as the fragment
shader won't exist and no color buffer will be bound.

Note that, when no render target is specified, the physical size of the
viewport must be explicitly specified, as Bevy has no other mechanism to
determine it.

A new example, `render_depth_to_texture`, has been added, containing a
rotating cube and a depth-only camera orbiting it. The depth texture
that the camera produces is rendered onto a plane using a custom shader.
(NB: In such scenarios, the depth texture must be copied from the camera
to a custom image due to (a) the `wgpu` limitation that a depth texture
can't be both a render target and bindable as a texture and (b) the fact
that Bevy depth textures are managed by Bevy itself and exposed only to
the render world. The example uses a custom render node to perform the
copy.) The depth-only camera can be moved using the WASD keys.

<img width="2564" height="1500" alt="Screenshot 2025-09-02 080508"
src="https://github.com/user-attachments/assets/415e7f4d-393d-4be3-b569-829c06901078"
/>
2025-09-03 03:18:39 +00:00
JMS55 7c88623e5e Solari PicaPica scene (#20658)
# Objective
- Improve the Solari example to showcase the feature's strengths better
(emissive meshes, dynamic lighting conditions)

I used the SEED PicaPica project, which besides being a great fit and
compact, is pretty cool as it's also was one of the first demos for
realtime raytracing :)

## Showcase
<img width="3206" height="1875" alt="image"
src="https://github.com/user-attachments/assets/be93211e-d2d0-4c7d-8f1d-1aa960087d9a"
/>
2025-09-03 02:28:23 +00:00
ickshonpe cd7e846f2b ui_target_camera example (#20827)
# Objective

Add a basic example demonstrating `UiTargetCamera` and camera ordering.

## Showcase

<img width="500" alt="image"
src="https://github.com/user-attachments/assets/6532600b-3e54-4835-85da-31dc4ecdc883"
/>
2025-09-02 21:11:32 +00:00
charlotte 🌸 1c10a425d3 Use web assets for meshlet example (#20795)
We have web assets now, let's use them!

---------

Co-authored-by: François Mockers <francois.mockers@vleue.com>
2025-08-31 07:39:59 +00:00
atlv cbf989c9da WebAssets without filtering (#20628)
# Objective

- adopt #17889
- Fixes #5061

---------

Co-authored-by: Peter Hayman <peteyhayman@gmail.com>
Co-authored-by: François Mockers <francois.mockers@vleue.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: jf908 <jf908@users.noreply.github.com>
Co-authored-by: François Mockers <mockersf@gmail.com>
Co-authored-by: jf908 <josh@thefindons.com>
2025-08-29 03:23:11 +00:00
VitalyR 805bf1307d examples: migrate async sleep to futures-timer; drop async-std (#19113)
# Objective

- Fixes #19055 

## Solution

- Replace `async-std` with `futures-timer`.

## Testing

CI

---------

Co-authored-by: James Liu <contact@jamessliu.com>
2025-08-27 10:27:19 +00:00
atlv c24491e449 Clean up root toml features (#20752)
# Objective

- We currently specify transitive feature dependencies in two places:
bevy and bevy_internal Cargo.tomls
- This means they get out of sync often, accumulate unnecessary
duplication, and sometimes forget certain transitive deps.

## Solution

- Standardize on bevy_internal. Why: this makes it impossible to use it
incorrectly if you depend on bevy_internal directly for some reason. If
we standardized on bevy Cargo.toml holding these, it would mean that
they could be bypassed by depending on bevy_internal. Not sure why
someone would do that, but this feels right.
- Move the few transitive feature dependency specifications that are
still in bevy to bevy_internal
- clean up a lot of duplicates
- add a few missing dependencies
- add top level bevy_mesh, bevy_camera, bevy_light, and bevy_shader
features.


## Testing

- this stuff is hard to test automatically or comprehensively. #20741
might make it easy to have a no-render test suite we can maintain
coverage for, but other than that its just manual verification.
2025-08-26 23:21:52 +00:00
ickshonpe 9fb232991a UI drag and drop example (#20673)
# Objective

Add a basic UI drag and drop example.

## Solution

Lots of observers.

## Testing

The displacement of the dragged UI nodes is wrong if you have scale
factor set, #20672 fixes this.
2025-08-26 02:43:31 +00:00
ickshonpe 6eb12806a9 Text2d multi target scale factors support (#20656)
# Objective

Use the scale factor of the render target for `Text2d` entities, instead
of always using the scale factor of the primary window.

Fixes #17342
Fixes #1890

## Solution

Iterate the cameras, find the first camera with `RenderLayers`
intersecting the `Text2d` entity's `RenderLayers` and use that camera's
target's scale factor.

This also allows us to remove the `bevy_window` dependency from
`bevy_sprite_render` and make it optional for `bevy_sprite` on the
"bevy_sprite_picking_backend" feature.

`Text2d` is still limited to generating only one text layout per
`Text2d` entity. If a `Text2d` entity is simultaneously rendered to
multiple targets with different scale factors then the maximum of the
target scale factors is used.

## Testing

I think I'm using `RenderLayers` and `VisibleEntities` correctly, and my
tests and the examples seem to work, but it would be best if a rendering
SME gave this a glance just to to make sure that I'm not doing something
naive.

Comes with a new example `multi_window_text` that can be used for
testing:
```
cargo run --example multi_window_text
```
If the changes are working correctly, the secondary window's text should
be twice as big as the primary window's text without blurriness.

## Showcase

<img width="642" alt="primary"
src="https://github.com/user-attachments/assets/547edf21-5c6e-4a95-ac8b-1b08b1c1364e"
/>

<img width="642" alt="secondary"
src="https://github.com/user-attachments/assets/b38d278d-64bc-4a90-9b11-0ac27d3a02bb"
/>

All the text uses a font-size of `30`. The secondary window has a scale
factor of `2.`, so the secondary window's text uses glyphs drawn at
double the resolution. On main, `Text2d` use glyphs drawn at the same
size for both windows, and so the text drawn with `Text2d` to the
secondary window is blurry:

<img width="642" alt="secondary_main"
src="https://github.com/user-attachments/assets/1aa3a523-e1d4-4196-a13c-d6ac8aa34cf3"
/>
2025-08-26 02:40:54 +00:00