Skip to content

Local named Z layers for bevy_ui_render - #26260

Open
ickshonpe wants to merge 38 commits into
bevyengine:mainfrom
ickshonpe:UiSubZLayer
Open

ickshonpe wants to merge 38 commits into
bevyengine:mainfrom
ickshonpe:UiSubZLayer

Conversation

@ickshonpe

@ickshonpe ickshonpe commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Objective

Replace the hardcodf32 z-offsets that we add to the stack index to order each element with local named Z layers that can be ordered relative to each other.

Related issues (doesn't exactly solve) #1275, #24564.

Solution

Add paint layers to bevy_ui_render.

The PaintOrder resource holds the list of paint layers, in the order they’re drawn from back to front..

The built-in layers are identified by the NodePaintLayer enum:

pub enum NodePaintLayer {
    BoxShadow,
    BackgroundColor,
    Border,
    Gradient,
    BorderGradient,
    Image,
    Material,
    TextSelection,
    Text,
    TextStrikethrough,
    TextCursor,
    InlineImage,
}

UiRenderPlugin initializes PaintOrder with all the builtin layers in the correct order.

Custom layers

To create a new PaintLayer, you derive PaintLayer:

#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, PaintLayer)]
pub struct MyPaintLayer;

Or you can define multiple layers at once with an enum:

#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, PaintLayer)]
pub enum MyPaintLayers {
    Back,
    Middle,
    Front,
}

Ordering

  • insert_before_layer / insert_after_layer place a layer directly below or above an existing layer.
  • insert_top / insert_bottom place a layer above or below all the other layers.
  • remove_layer removes a layer. A built-in element whose layer is removed isn't drawn.

The insert methods move the layer if it's already present.

The UiMaterial trait has a new paint_layer() method that chooses the layer the layer the material is drawn to.
It defaults to NodePaintLayer::Material.

PaintOrder just newtypes an IndexSet, so you can also use the IndexSet methods to reorder it arbitrarily.

Extraction

Extraction functions should look up the z-offsets for their elements layer with PaintOrder::get_offset, which returns a value in the range 0.0..1.0. The z-offset should be looked up once at the start of the extraction function, and shouldn't be looked up per node if at all possible.

The PaintOrder resource is also extracted separately, so the offsets can be applied in some queue functions instead for some elements. This is because extraction isn't as centralized as it should be.

Changing PaintOrder at all is expensive as it triggers a reextraction of all elements.

Implementation

  • The paint_layers module contains all the new functionality.

  • The proc macro for the PaintLayer label derive is in a new rendlayers/macros subscrate. It's adapted from bevy_render's macros crate.

  • The paint order is global. There's no builtin support for reordering painting per node.

Testing

The UI testbed shouldn't exhibit any changes:

cargo run --example testbed_ui

There are some tests for PaintOrder in the paint_layers module.

AI Disclosure

I used claude to work out some errors with the macro crate to get the imports and paths right so it would compile, and write most of the paint_layers tests.

@ickshonpe ickshonpe added A-UI Graphical user interfaces, styles, layouts, and widgets X-Contentious There are nontrivial implications that should be thought through S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Oct 21, 2026
@github-project-automation github-project-automation Bot moved this to Needs SME Triage in UI Oct 21, 2026
@ickshonpe ickshonpe added D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes D-Macros Code that generates Rust code A-Rendering Drawing game state to the screen and removed X-Contentious There are nontrivial implications that should be thought through labels Oct 21, 2026
@github-project-automation github-project-automation Bot moved this to Needs SME Triage in Rendering Oct 21, 2026
@Zeophlite Zeophlite added the AI-Assisted Discloses the use of AI in any way label Oct 22, 2026
@ickshonpe ickshonpe closed this Oct 26, 2026
@github-project-automation github-project-automation Bot moved this from Needs SME Triage to Done in UI Oct 26, 2026
@github-project-automation github-project-automation Bot moved this from Needs SME Triage to Done in Rendering Oct 26, 2026
@ickshonpe

Copy link
Copy Markdown
Contributor Author

Closed by accident.

@ickshonpe ickshonpe reopened this Oct 26, 2026
@github-project-automation github-project-automation Bot moved this from Done to Needs SME Triage in UI Oct 26, 2026
@github-project-automation github-project-automation Bot moved this from Done to Needs SME Triage in Rendering Oct 26, 2026
UiSubZLayer -> PaintLayer
UiZubZLayers -> NodePaintLayers
bevy_ui_render::sub_z_layers -> bevy_ui_render::paint_layers
Now it wraps an `IndexSet` instead of `Vec`.
Added a `get_layer_index` helper function to replace the duplicated error handling code in the methods.
More idiomatic From impls.
Renamed `insert_before`/`after` to `insert_before_label`/ `after_label` to avoid shadowing.
Added `remove_layer` method to `PaintOrder`
Added tests sub module with default order test
If you insert the same label twice in the from impls, the label is moved to the second position.
@ickshonpe ickshonpe added M-Release-Note Work that should be called out in the blog due to impact M-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide labels Oct 26, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Rendering Drawing game state to the screen A-UI Graphical user interfaces, styles, layouts, and widgets AI-Assisted Discloses the use of AI in any way D-Macros Code that generates Rust code D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes M-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide M-Release-Note Work that should be called out in the blog due to impact S-Needs-Review Needs reviewer attention (from anyone!) to move forward

Projects

Status: Needs SME Triage
Status: Needs SME Triage

Development

Successfully merging this pull request may close these issues.

2 participants