Crate bevy_ecss

source ·
Expand description

Bevy

MIT/Apache 2.0 Realease Doc Rust Crate Bevy tracking

Bevy ECSS

What is Bevy ECSS?

Bevy ECSS is a crate which allows the usage of a subset of CSS to interact with bevy_ecs. It’s mainly aimed to apply styling on bevy_ui but it can be used by any component by implementing custom properties.

Why the name?

Just because Bevy ECS + CSS is a perfect fit!

Usage

To use Bevy ECSS just add a StyleSheet with a loaded css file to any entity and all style sheet rules will be applied to the entity and all its descendants (children of children of children and so on).

use bevy::prelude::*;
use bevy_ecss::prelude::*;

fn setup_awesome_ui(root: Entity, mut commands: Commands, asset_server: Res<AssetServer>) {
    commands
        .entity(root)
        .insert(StyleSheet::new(asset_server.load("sheets/awesome.css")));
}

That’s it, now your UI will indeed look awesome!

CSS Subset

Bevy ECSS only supports a subset of CSS at moment, since many properties and features requires more advanced selectors, components and properties which currently isn’t implemented.

Here you can find a list of all currently supported selectors and properties:

Selectors

TypeDetailsExample
NameSelects by using bevy built-int Name component.#inventory { ... }
ClassSelects by using Class component, which is provided by Bevy ECSS..enabled { ... }
ComponentSelects by using any component, but it has to be registered before usage. You can find more details bellow.button { ... }

You may combine any of the above selector types to create a complex selector, if you like so. For instance, window.enabled.pop-up select all windows, which are enabled and are of pop-up type. The same rules of CSS Class selectors applies here.

This assumes that window is a bevy_ecs component and was registered before usage. Also assumes the entities has the Class component with at least enabled pop-up class name.

Aditionally, Bevy ECSS also supports descendant combinator which selects all entities that are descendant the given selector tree.

#quest-window text {
    color: red;
}

The above rule will match all entities which has a Text component and is descendant of any entity which as a Name component which the value of quest-window.

So it’s possible to combine complex composed selectors with descendant combinator.

#main-menu button.enabled .border {
    background-color: #ff03ab;
}

This rule will match all components which has a Class with the value of border and are descendant of any entity which has a button component and a Class component with the value of enabled and also are descendant of any entity which has a Name component with value main-menu.

Properties

Here is a list of all currently supported properties. Note that these are properties which are provived by Bevy ECSS but you can also add your own properties at anytime.

Before reading properties description, we’ll use this notation to describe accepted values:

NotationDescription
00.00%Any percent value, like 93% or 4.45%
00.00pxAny dimensional value, like 11px or 0.99px
00.00Any number value, like 0 or 14.2
<ident> | <ident>Only one of the identifiers are allowed, without quotes, like none or hidden
<area-short-hand>Allows the short hand area constructor by using either dimensions or percentage, like 10px or 5% 10px 3%. No global values, or auto keyword is supported yet

Style properties

PropertyValuesDescription
displayflex | noneApplies the display property on display field of all sections on matched Style components.
position-typeabsolute | relativeApplies the position-type property on position_type field of all sections on matched Style components.
directioninherit | left-to-right | right-to-leftApplies the direction property on direction field of all sections on matched Style components.
flex-directionrow | column | row-reverse | column-reverseApplies the flex-direction property on flex_direction field of all sections on matched Style components.
flex-wrapno-wrap | wrap | wrap-reverseApplies the flex-wrap property on flex_wrap field of all sections on matched Style components.
align-itemsflex-start | flex-end | center | baseline | stretchApplies the align-items property on align_items field of all sections on matched Style components.
align-selfauto | flex-start | flex-end | center | baseline | stretchApplies the align-self property on align_self field of all sections on matched Style components.
align-contentflex-start | flex-end | center | stretch | space-between | space-aroundApplies the align-content property on align_content field of all sections on matched Style components.
justify-contentflex-start | flex-end | center | space-between | space-around | space-evenlyApplies the justify-content property on justify_content field of all sections on matched Style components.
overflowvisible | hiddenApplies the overflow property on overflow field of all sections on matched Style components.
left00.00% | 00.00pxApplies the property on position.left field of all matched components.
right00.00% | 00.00pxApplies the property on position.right field of all matched components.
top00.00% | 00.00pxApplies the property on position.top field of all matched components.
bottom00.00% | 00.00pxApplies the property on position.bottom field of all matched components.
width00.00% | 00.00pxApplies the property on size.width field of all matched components.
height00.00% | 00.00pxApplies the property on size.height field of all matched components.
min-width00.00% | 00.00pxApplies the property on min_size.width field of all matched components.
min-height00.00% | 00.00pxApplies the property on min_size.height field of all matched components.
max-width00.00% | 00.00pxApplies the property on max_size.width field of all matched components.
max-height00.00% | 00.00pxApplies the property on max_size.height field of all matched components.
flex-basis00.00% | 00.00pxApplies the property on max_size.height field of all matched components.
flex-grow0 | 1 | 2Applies the property on flex_grow field of all matched components.
flex-shrink0 | 1 | 2Applies the property on flex_shrink field of all matched components.
aspect-ratio00.00 | noneApplies the property on aspect_ratio field of all matched components.
margin<area-short-hand>Applies the property on margin field of all matched components.
padding<area-short-hand>Applies the property on padding field of all matched components.
border<area-short-hand>Applies the property on border field of all matched components.

Text properties

PropertyValuesDescription
colornamed-colors | hex_colorsApplies the property on style.color for all sections of matched components.
font"path/to/font.ttf"Applies the property on style.font for all sections of matched components.
font-size00.00Applies the property on style.font_size for all sections of matched components.
text-content"Some text value"Applies the property on value for all sections of matched components.
text-alignleft | center | rightApplies the property on alignment of all matched components.

Components properties

PropertyValuesDescription
background-colornamed-colors | hex_colorsApplies the property on BackgroundColor of all matched components.

Component Selector Builtin

Bevy ECSS provites the following components selector:

SelectorComponent
background-colorBackgroundColor
textText
buttonButton
nodeNode
styleStyle
ui-imageUiImage
interactionInteraction

This list will be expanded to match bevy_ui and other bevy core components.

Custom Component Selector

You may also register your own components or alias/overwrite builtin components selector.

use bevy::prelude::*;
use bevy_ecss::prelude::*;

#[derive(Component)]
struct MyFancyComponentSelector;

#[derive(Component)]
struct FancyColor;

fn some_main() {
    let mut app = App::new();
    app.add_plugins(DefaultPlugins).add_plugin(EcssPlugin::default());
    // You may use it as selector now, like
    // fancy-pants {
    //      background-color: pink;
    // }
    app.register_component_selector::<MyFancyComponentSelector>("fancy-pants");
    // Or you can overwrite a component selector.
    app.register_component_selector::<FancyColor>("background-color");
}

Custom Property

It’s also possible to implement your own properties, be it part of CSS standard or not. Let’s implement a custom alpha property with will set the alpha channel of any BackgroundColor.


#[derive(Default)]
pub(crate) struct AlphaProperty;

impl Property for AlphaProperty {
    // This is the cached value to be used when applying the property value.
    // It is evaluated only on the first time and futures runs are cached for performance reasons.
    type Cache = f32;
    // Which components the property needs when applying the cached value.
    // It is the same as using bevy_ecs Query<C, F>.
    type Components = &'static mut BackgroundColor;
    // If this property can be set only when there is another property, it's possible to filter here.
    // It's not recommended to use only With<> and Without<>.
    type Filters = ();

    fn name() -> &'static str {
        // The name of property. prefer kebab-case for consistency.
        "alpha"
    }

    fn parse<'a>(values: &PropertyValues) -> Result<Self::Cache, EcssError> {
        // PropertyValues::f32 tries to parse property value into a numeric value
        if let Some(value) = values.f32() {
            Ok(value)
        } else {
            Err(EcssError::InvalidPropertyValue(Self::name().to_string()))
        }
    }

    // This function will be called for every entity matched on every rule selector.
    fn apply<'w>(
        cache: &Self::Cache,
        mut components: QueryItem<Self::Components>,
        _asset_server: &AssetServer,
        _commands: &mut Commands,
    ) {
        components.0.set_a(*cache);
    }
}

Now just register the property on App:

app.register_property::<AlphaProperty>();

Done! Whenever an alpha property is found on any css file, the AlphaProperty will be applied. You can find this full example here.

Bevy support table

bevybevy_ecss
0.80.1
0.90.2
0.100.3

Contributing

Got some idea, feedback, question or found any bug? Feel free to open an issue at any time!

License

Bevy ECSS is dual-licensed under either:

This means you can select the license you prefer! This dual-licensing approach is the de-facto standard in the Rust ecosystem and there are very good reasons to include both.

Modules

  • use bevy_ecss::prelude::*; to import common components, and plugins and utility functions.

Structs

  • Sets the entities class to be matched by selectors in oncss.
  • Plugin which add all types, assets, systems and internal resources needed by bevy_ecss. You must add this plugin in order to use bevy_ecss.
  • A list of PropertyToken which was parsed from a single property.
  • A selector parsed from a css rule. Each selector has a internal hash used to differentiate between many rules in the same sheet.
  • Represents a single rule inside a style sheet with a Selector which determines which entities should be applied the PropertyValues.
  • Applies a StyleSheetAsset on the entity which has this component.
  • A cascading style sheet (css) asset file.

Enums

  • Errors which can happens while parsing css into Selector or Property.
  • System sets used by bevy_ecss systems
  • A property value token which was parsed from a CSS rule.
  • Represents a selector element on a style sheet rule. A single selector can have multiple elements, for instance a selector of button.enabled Would generated two elements, one for button and another for .enabled.

Traits