Expand description

§
Blazingly fast retained layout engine for Bevy entities, built around vanilla Bevy ECS. It gives you the ability to make your own custom UI using regular ECS like every other part of your app.
-
Any aspect ratio: Lunex is designed to support ALL window sizes out of the box without deforming. The built in layout types react nicely and intuitively to aspect ratio changes.
-
Optimized: Unlike immediate mode GUI systems, Bevy_Lunex is a retained layout engine. This means the layout is calculated and stored, reducing the need for constant recalculations and offering potential performance benefits, especially for static or infrequently updated UIs.
-
ECS focused: Since it’s built with ECS, you can extend or customize the behavior of your UI by simply adding or modifying components. The interactivity is done by regular systems and events.
-
Worldspace UI: One of the features of Bevy_Lunex is its support for both 2D and 3D UI elements, leveraging Bevy’s
Transformcomponent. This opens up a wide range of possibilities for developers looking to integrate UI elements seamlessly into both flat and spatial environments. Diegetic UI is no problem.
§

Try out the live WASM demo on
Itch.io(Limited performance & stutter due to running on a single thread). For best experience compile the project natively.
§Syntax Example
This is an example of a clickable Button created from scratch using provided components. Thanks to ECS, the syntax is highly modular with strong emphasis on components-per-functionality. As you can see, it is no different from vanilla Bevy ECS.
// Create UI
commands.spawn((
// Initialize the UI root for 2D
UiLayoutRoot::new_2d(),
// Make the UI synchronized with camera viewport size
UiFetchFromCamera::<0>,
)).with_children(|ui| {
// Spawn a button in the middle of the screen
ui.spawn((
Name::new("My Button"),
// Specify the position and size of the button
UiLayout::window().pos(Rl((50.0, 50.0))).size((200.0, 50.0)).pack(),
// When hovered, it will request the cursor icon to be changed
OnHoverSetCursor::new(SystemCursorIcon::Pointer),
)).with_children(|ui| {
// Spawn a child node but with a background
ui.spawn((
// You can define layouts for multiple states
UiLayout::new(vec![
// The default state, just fill the parent
(UiBase::id(), UiLayout::window().full()),
// The hover state, grow to 105% of the parent from center
(UiHover::id(), UiLayout::window().anchor(Anchor::Center).size(Rl(105.0)))
]),
// Enable the hover state and give it some properties
UiHover::new().forward_speed(20.0).backward_speed(4.0),
// You can specify colors for multiple states
UiColor::new(vec![
(UiBase::id(), Color::BEVYPUNK_RED.with_alpha(0.15)),
(UiHover::id(), Color::BEVYPUNK_YELLOW.with_alpha(1.2))
]),
// You can attach any form of rendering to the node, be it sprite, mesh or something custom
Sprite {
image: asset_server.load("images/button.png"),
// Here we enable sprite slicing
image_mode: SpriteImageMode::Sliced(TextureSlicer { border: BorderRect::all(32.0), ..Default::default() }),
..Default::default()
},
// Make sure it does not cover the bounding zone of parent
Pickable::IGNORE,
)).with_children(|ui| {
// Spawn a text child node
ui.spawn((
// For text we always use window layout to position it. The size is computed at runtime from text bounds
UiLayout::window().pos((Rh(40.0), Rl(50.0))).anchor(Anchor::CenterLeft).pack(),
UiColor::new(vec![
(UiBase::id(), Color::BEVYPUNK_RED),
(UiHover::id(), Color::BEVYPUNK_YELLOW.with_alpha(1.2))
]),
UiHover::new().forward_speed(20.0).backward_speed(4.0),
// Here we specify the text height proportional to the parent node
UiTextSize::from(Rh(60.0)),
// You can attach text like this
Text2d::new("Click me!"),
TextFont {
font: asset_server.load("fonts/semibold.ttf"),
font_size: 64.0,
..Default::default()
},
// Make sure it does not cover the bounding zone of parent
Pickable::IGNORE,
));
});
})
// Utility observers that enable the hover state on trigger
.observe(hover_set::<Pointer<Over>, true>)
.observe(hover_set::<Pointer<Out>, false>)
// Interactivity is done through observers, you can query anything here
.observe(|_: Trigger<Pointer<Click>>| {
println!("I was clicked!");
});
});§Documentation
-
The Lunex Book:
Bevy Lunex book. -
Highly documented source code on Docs.rs:
Docs.rs. -
Highly documented production-ready example:
Bevypunk example.
§Contributing
Any contribution submitted by you will be dual licensed as mentioned below, without any additional terms or conditions. If you have the need to discuss this, please contact me.
§Licensing
Released under both APACHE and MIT licenses. Pick one that suits you the most!
Modules§
Structs§
- Ab
- Absolute - Represents non-changing unit. Scale can be modified but by default
1Ab = 1Px. - Align
- Align - A type used to define alignment in a node layout.
- Cursor
Icon Queue - Cursor
Plugin - Dimension
- Dimension - This component holds width and height used for different Ui components
- Em
- Size of M - Represents unit that is the size of the symbol
M. Which is16pxwithfont size 16pxand so on. - Gamepad
Attached Cursor - This component is used for SoftwareCursor-Gamepad relation.
- Gamepad
Cursor - This will make the
SoftwareCursorcontrollable by a gamepad. - Lunex
Gizmo Group2d - Gizmo group for UI 2D node debug outlines
- Lunex
Gizmo Group3d - Gizmo group for UI 3D node debug outlines
- NoLunex
Picking - This component disables the Lunex picking backend for this entity.
Use this only if you want to use a different or custom picking
bakckend. To disable picking entirely, use
Pickable::IGNORE. - OnHover
SetCursor - Requests cursor icon on hover
- Recompute
UiLayout - Trigger this event to recompute all
UiLayoutRootentities. - Rectangle2D
- Rectangle 2D - Contains computed values from node layout.
- Rh
- Relative height - Represents scalable unit
0% to 100%.120%is allowed. Proportional to a height measure even when used in a width field. - Rl
- Relative - Represents scalable unit
0% to 100%.120%is allowed. - Rw
- Relative width - Represents scalable unit
0% to 100%.120%is allowed. Proportional to a width measure even when used in a height field. - Software
Cursor - Component for creating software mouse.
- Text
Animator - This component modifies attached
Text2dwith a modified string outputted from a time dependant function. - UiBase
- Ui Base - The default state for a Ui-Node, used only for the
UiBase::idkey. It is not a component that you can control. - UiClicked
- WORK IN PROGRESS
- UiColor
- Ui Color - This component is used to control the color of the Ui-Node. It is synchronized with a state machine and allows for specifying unique colors for each state.
- UiEmbedding
- Ui Embedding - Use this component to mark entities whose texture handles are embeddings instead of regular assets.
This means Lunex will resize the actual texture source when
Dimensionhas changed. - UiFetch
From Camera - Ui Fetch From Camera - Attaching this component to
UiLayoutRootwill make theDimensioncomponent pull data from aCamerawith attachedUiSourceCamerathat has the same index. - UiHover
- Ui Hover - A built in state that should be triggered manually when a pointer hovers over a Ui-Node. This state first needs to be enabled for the entity by adding it as a component.
- UiHover
Set - Event that enables the hover transition
- UiImage
Size - Ui Image Size - This component makes image size the authority instead.
- UiIntro
- WORK IN PROGRESS
- UiLayout
- Ui Layout - This component specifies the layout of a Ui-Node, which must be spawned as a child
of either
UiLayoutRootorUiLayoutto work. Based on the provided layout other attached components on this entity are overwritten to match the computed structure. - UiLayout
Root - Ui Layout Root - This component marks the start of a worldspace Ui-Tree. Spawn this standalone for worldspace 3D UI or spawn this as a child of camera for a HUD. For 2D UI, if your camera does not move you can spawn it standalone too.
- UiLayout
Type Boundary - Boundary - Declarative layout type that is defined by its top-left corner and bottom-right corner.
- UiLayout
Type Solid - Solid - Declarative layout type that is defined by its width and height ratio.
- UiLayout
Type Window - Window - Declarative layout type that is defined by its size and position.
- UiLunex
Anim Plugin - This plugin is used for the main logic.
- UiLunex
Debug Plugin - This plugin is used to enable debug functionality.
- UiLunex
Index Plugin - This plugin is used to register index components.
- UiLunex
Picking Plugin - Adds picking support for Lunex.
- UiLunex
Plugin - This plugin is used for the main logic.
- UiLunex
Plugins - Plugin group adding all necessary plugins for Lunex
- UiLunex
State Plugin - This plugin is used for the main logic.
- UiMesh
Plane2d - Ui Mesh Plane 2d - This component is used to mark mesh entities that can be freely replaced with quad mesh on demand.
- UiMesh
Plane3d - Ui Mesh Plane 3d - This component is used to mark mesh entities that can be freely replaced with quad mesh on demand.
- UiOutro
- WORK IN PROGRESS
- UiRoot3d
- Ui Root 3d - This is a marker component for all entities which fall under a 3D UI. You can check through this component if a specific node is 2D or 3D without looking for its root.
- UiSelected
- WORK IN PROGRESS
- UiSource
Camera - Ui Source Camera - Marks a
Cameraas a source forUiLayoutRootwithUiFetchFromCamera. They must have the same index and only oneUiSourceCameracan exist for a single index. - UiState
- Ui State - This component aggrages state transition values for later reference by other components. You don’t directly control or spawn this component, but use an abstraction instead. You can use the prebuilt state components or create a custom ones with a completely unique transition logic. You just have to provide transition value to this component later.
- UiText
Size - Ui Text Size - This component is used to control the size of a text compared
to other Ui-Nodes. It works by overwritting the attached
UiLayoutwindow size parameter to match the text bounds. The value provided is used as a scale to adjust this size, specificaly it’s height. It is recommended to usenon-relativeunits such asAb,Rw,Rh,Vh,VwandEmfor even values. - UiValue
- Ui value - A collection of different units used for UI.
They are computed at runtime when layout is being calculated (context-aware).
The supported units that implement
Into<UiValue>are: - Vh
- Viewport Height - Represents scalable unit
0% to 100%of the root container.120%is allowed. Proportional to a height measure even when used in a width field. - Vp
- Viewport - Represents scalable unit
0% to 100%of the root container.120%is allowed. - Vw
- Viewport width - Represents scalable unit
0% to 100%of the root container.120%is allowed. Proportional to a width measure even when used in a height field.
Enums§
- Gamepad
Cursor Mode - This struct defines how should the cursor movement behave.
- Scaling
- Scaling - A type used to define how should a Solid node layout scale relative to a parent.
- UiDepth
- Ui Depth - This component overrides the default Z axis (depth) stacking order. This is useful when fixing Z order flickering. Another use can be offseting an background image for example.
- UiLayout
Type - Ui Layout Type - Enum holding all UI layout variants.
- UiSystems
- System set for
UiLunexPlugins
Traits§
- Camera
Texture Render Constructor - Provides utility costructor methods for
Camera - Image
Texture Constructor - Provides utility constructor methods for
Image - Nice
Display - Nice display - Special trait for formatted console debug output with colors.
- UiState
Trait - Trait that all states must implement before being integrated into the state machine.
- UiValue
Evaluate - Trait for implementing evaluation logic for
(T).
Functions§
- decryption_
animation - Creates a decryption effect where random symbols gradually become the actual text
- default_
linear_ curve - Default linear curve used for reflection defaults
- hover_
set - Utility observer that triggers the
UiHoverSetevent on triggered event. - observer_
touch_ layout_ root - This observer will mutably touch
UiLayoutRootwhich will triggersystem_layout_compute. - scrambled_
reveal_ animation - Reveals characters in a scrambled order
- slide_
in_ animation - Creates a slide-in effect where characters come in from the sides
- system_
color - This system takes care of
UiColordata and updates querriedSpriteandTextColorcomponents. and updatesColorMaterialandStandardMaterial - system_
debug_ draw_ gizmo_ 2d - This system draws the outlines of
UiLayoutandUiLayoutRootas gizmos. - system_
debug_ draw_ gizmo_ 3d - This system draws the outlines of
UiLayoutandUiLayoutRootas gizmos. - system_
debug_ print_ data - This system traverses the hierarchy and prints the debug information.
- system_
embedd_ resize - This system takes
Dimensiondata and pipes them into querriedHandle<Image>data to fit. This will resize the original image texture. - system_
fetch_ dimension_ from_ camera - This system takes
Cameraviewport data and pipes them into querriedDimension+UiLayoutRoot+UiFetchFromCamera. - system_
image_ size_ to_ layout - This system takes updated
Handle<Image>data and overwrites corespondingUiLayoutdata to match the text size. - system_
layout_ compute - This system traverses the hierarchy and computes all nodes.
- system_
mark_ 3d - This system traverses the hierarchy and adds
UiRoot3dcomponent to children. - system_
mesh_ 2d_ reconstruct_ from_ dimension - This system takes
Dimensiondata and constructs a plane mesh. - system_
mesh_ 3d_ reconstruct_ from_ dimension - This system takes
Dimensiondata and constructs a plane mesh. - system_
pipe_ sprite_ size_ from_ dimension - This system takes
Dimensiondata and pipes them into querriedSprite. - system_
recompute_ on_ change - system_
state_ base_ balancer - This system controls the
UiBasestate. This state is decreased based on total sum of all other active states. - system_
state_ hover_ update - This system updates the hover transition value over time
- system_
state_ pipe_ into_ manager - This system pipes the attached state component data to the
UiStatecomponent. - system_
text_ 3d_ size_ from_ dimension - This system takes
Text3dDimensionOutdata and pipes them into querriedTransformscale. - system_
text_ 3d_ size_ to_ layout - This system takes updated
Text3dDimensionOutdata and overwrites corespondingUiLayoutdata to match the text size. - system_
text_ size_ from_ dimension - This system takes
TextLayoutInfodata and pipes them into querriedTransformscale. - system_
text_ size_ to_ layout - This system takes updated
TextLayoutInfodata and overwrites corespondingUiLayoutdata to match the text size. - system_
touch_ camera_ if_ fetch_ added - This system listens for added
UiFetchFromCameracomponents and if it finds one, mutable accesses allCameras to trigger fetching systems. - typing_
animation_ cursor - Simulates typing animation with an vertical line cursor
- typing_
animation_ underscore - Simulates typing animation with an underscore cursor