2 unstable releases

Uses new Rust 2024

0.2.0 Apr 30, 2025
0.1.0 Jan 24, 2025

#608 in Game dev

Download history 134/week @ 2025-01-22 30/week @ 2025-01-29 22/week @ 2025-02-05 8/week @ 2025-02-12 4/week @ 2025-02-19 18/week @ 2025-02-26 6/week @ 2025-03-05 3/week @ 2025-03-12 3/week @ 2025-03-26 142/week @ 2025-04-30 16/week @ 2025-05-07

158 downloads per month

MIT/Apache

1MB
13K SLoC

About

Crates.io docs.rs

Bevy Flair enables developers to style Bevy UI interfaces using familiar CSS syntax.

With Bevy Flair, you can define the appearance and layout of Bevy UI components efficiently, leveraging the simplicity and power of CSS.

Features

  • Use CSS assets to apply format to any Bevy UI element.
  • Inherited stylesheets. Just specify the stylesheet using NodeStyleSheet in the root node, and all children will inherit the same stylesheet.
  • Support for css reloading. Just edit your .css files and the styles will be re-applied on the fly. This is one of the main advantages over specifying the styles directly.
  • Almost All existing UI components and properties are supported:
  • Use of non-standard css to support ImageNode (e.g: background-image: url("panel-border-030.png"), background-image-mode: sliced(20.0px)).
  • Color parsing. (e.g. red,#ff0000,rgb(255 0 0),hsl(0 100% 50% / 50%),oklch(40.1% 0.123 21.57))
  • Most common css selectors works by default (Thanks to selectors crate).
    • :root selector
    • #id selector. Works by using the Name component
    • .class selector. Works by using the ClassList component
    • Type selector. Works by using the TrackTypeNameComponentPlugin plugin configured by default to track: Node, Button, Label and Text,
    • :hover, :active and :focus pseudo class selectors. :hover and :active are automatically tracked for buttons.
    • :nth-child(_), :first-child works just fine. e.g: :nth_child(2n + 1)
  • Most common css selector combinators (Thanks to selectors crate):
    • Descendant: ul.my-things li.
    • Child: ul.my-things > li.
    • Next sibling: img + p.
    • Subsequent-sibling: img ~ p.
  • Fancy selectors like :not(), :has(), :is() and :where().
  • Nested selectors are supported.
    • You can add &:hover { .. } inside a selector and it will work.
  • Import other stylesheets using @import.
  • Support for custom properties using var().
    • Fallback is currently not supported
  • Basic support for calc expressions using calc().
    • This is currently limited by Bevy support of mixing different types. For example, this cannot not work currently: calc(100% - 20px).
    • Currently, is valuable to do calculations using vars. For example: calc(var(--spacing) * 2).
  • Support for inherited properties (e.g. color, font-family are inherited by default).
  • Font loading support using @font-face.
  • Animated property changes using transition.
  • Custom animations using @keyframes.
  • Different stylesheets per subtree. With the use of a different NodeStyleSheet per subtree. It's even possible to not apply any style for a given subtree.
  • Supports for custom properties. (Example TBA)
  • Supports for custom parsing. (Example TBA)

Missing features and limitations

  • Multiple stylesheets at the same time. Right now it's restricted to a single stylesheet per entity.
    • This is partially mitigated by the use of @imports.
  • Global stylesheets. It's not possible to define a stylesheet that is applied everywhere.
  • Inline css. Right now it's not possible to define css directly in code. It has to be defined directly into an asset with the .css extension. It wouldn't be as easy as creating a simple macro for it, but it most definitely something to be considered.
  • Support for @media queries. It could be interesting to see what features make sense to implement.
  • Support for !important.
    • I don't really know if it's something people use nowadays. One possible first step would be detected the presence of an !important and ignore it (with a warning) instead of throwing a parse error.
  • Support for @layer.
    • Some modern frameworks like tailwind make use of this so it could be interesing to add support to.
  • Support for local fonts or support fallback fonts. Right now a single font is specified using @font-face. In bevy this should work for the majority of users.
  • Advance color parsing like using color-mix() or relative colors like lch(from blue calc(l + 20) c h).
    • This should be relatively easy to add.
  • Support for pre-processors like sass. It should be relatively simple to add crate that generates css from sass code.

Showcase

This example works by only using CSS (See example)

https://github.com/user-attachments/assets/792b9cfa-42fb-4e50-a85f-8d21aafeb1e5

Getting started

  1. Add bevy_flair to your Cargo.toml.

  2. Create your UI structure and attach NodeStyleSheet the root:

main.rs:

use bevy::prelude::*;
use bevy_flair::prelude::*;

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

fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
    commands.spawn(Camera2d);

    commands
        .spawn((
            Node::default(),
            NodeStyleSheet::new(asset_server.load("my_stylesheet.css")),
        ))
        .with_children(|parent| {
            parent
                .spawn((Button, Node::default()))
                .with_child(Text::new("Button"));
        });
}

Save your css file under assets/my_stylesheet.css:

:root {
  display: flex;
  width: 100%;
  height: 100%;
  align-items: center;
  justify-content: center;
  flex-direction: column;
}

Button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 150px;
  height: 65px;
  background-color: rgb(15%, 15.0%, 15.0%);
  border-radius: 30px;
  transition: background-color 0.3s;

  &:hover {
    background-color: rgb(25.0%, 25.0%, 25.0%);
  }

  &:active {
    background-color: rgb(35.0%, 75.0%, 35.0%);
  }

  Text {
    font-size: 35px;
    color: rgb(30% 30% 30%);
  }
}

You can see more examples in the examples folder.

Project goals

  • Support all Bevy UI features from css.
  • Efficient and reactive when applying styles.
    • If there are no modifications to the state of the UI tree, the styles should not be re-applied.
    • When modifications are detected in the UI tree, just the minimum affected nodes should get their style reapplied.
  • Invalid css should be reported and discarded.
    • Any unrecognized property should be reported, not silently ignored.
    • A badly written property should not stop the parsing of the rest of the css file
    • An invalid css select, should only affect its rule set, and not the rest of the css
    • No panics while parsing css.
  • Css that would make your application panic should be rejected and reported.
    • If any correctly parsed css can cause a panics in bevy, it should be treated as a bug.

Non goals

  • Care about how developers spawn the Bevy UI elements.
    • If you want to use any fancy macro to spawn your bevy UI elements, or if you want to do it in a manual way, it should not matter, it should work the same way.
  • Define a default style.
    • By default, if a property is not defined, such property will not be modified. This means that is up to the author to set up fallback styling if it's needed.
  • Support all css features / properties.
    • CSS is a vast specification, so there are plenty of features that might not make sense to support.
  • Being consistent with the css standard.
    • CSS is a standard and such it defines certain behaviours very well, for example, current implementation of animation or transition is quite possible not 100% consistent with the standard.
  • Implement missing Bevy UI features.
    • If a certain feature does not exist in bevy UI, it will not implement, e.g. it will not implement transform nor linear-gradient if bevy UI does not implement them.
    • There is always an option to implement custom properties with custom parsers.

Bevy compatibility

bevy bevy_flair
0.16 0.2
0.15 0.1

Contributing

Contributions are welcome! Feel free to fork the repository and submit a pull request.

License

This project is licensed under the MIT License. See the LICENSE file for more details.

The assets included in this repository (for our examples) fall under different open licenses.

Assets

Dependencies

~60–92MB
~1.5M SLoC