beet_ui
beet_ui represents structured documents as ECS data. It borrows the vocabulary of XML, nodes, elements and attributes, but treats a tree as a living thing in a Bevy world rather than a static file.
Trees are written with the rsx! macro, using familiar markup:
# use beet_ui::prelude::*;
rsx! {
<p style="color: pink">"Hello world!"</p>
};
which expands to plain entities and components:
# use beet_ui::prelude::*;
# use beet_core::prelude::*;
World::new().spawn((
Element::new("p"),
related!(Attributes[
(Attribute::new("style"), Value::new("color: pink"))
]),
children![ Value::new("Hello world!") ]
));
Leaning into ECS loosens XML's rules in useful ways. A single node can hold both an Element and a Value, the Value type covers both text nodes and attribute values, a value node can have children of its own, and an empty node is simply a fragment. The tree is composable in the way components are.
Reusable widgets are #[template] function components used as capitalized tags like <Button/>. The same tree feeds two kinds of integration: parsers diff a byte stream against an entity, and renderers walk the tree to produce output. The renderers are target-agnostic, so one scene becomes an HTML page or a character-cell terminal view without rewriting it. Styling follows the same principle, semantic Classes resolved by a rule set instead of stringly-typed CSS, which keeps the contract between widgets and styles in the type system. See the Design section for the system built on top.