Xerune is a lightweight, CPU-only native HTML/CSS rendering engine and UI framework designed for embedded Linux environments (like Raspberry Pi, QEMU, or custom board systems) without GPU/OpenGLES acceleration.
| Music Player | Showcase | Animation |
|---|---|---|
![]() |
![]() |
![]() |
High quality videos: Music Player, Showcase, Animation
- Model-View-Update (MVU) Architecture: Elm-style design providing predictable state transitions and unidirectional data flow.
- Compile-time template verification: Native type-safe data binding and layout generation.
- No GPU required: High-performance CPU-only rendering.
- Embedded hardware-ready: Dedicated backends for Linux Framebuffer (
/dev/fb0) and DRM/KMS with double buffering. - Input integration: Built-in support for mouse, keyboard, and
evdevtouch input bounds calibration. - CSS Stylesheets & Keyframe Animations: Parse inline styles, global styles, classes, IDs, gradients, borders, font weights, and keyframe animations.
- Canvas APIs: Support for custom user-drawn Canvas pixel buffers.
Xerune is built around the Model-View-Update (MVU) pattern:
- Model (
src/model.rs): Owns the application state. - View (
Model::view): Takes the model and outputs declarative UI templates. - Update (
Model::update): Mutates the model state based onMessageintents. - UI Layout & Style Engine (
src/ui/): Resolves HTML elements and CSS properties onto a Taffy Flexbox tree and generatesDrawCommands. - Runtime (
src/runtime/): Manages the main execution tick, message queues, and animation intervals.
- taffy: Flexbox & grid layout engine.
- html5ever: HTML parsing.
- winit & softbuffer: Desktop windowing backend.
- evdev: Linux touch & key input handling.
- drm: Linux Direct Rendering Manager control.
use xerune::{Model, InputEvent, Runtime, Context, XeruneTemplate};
#[derive(Default)]
struct AppModel {
counter: i32,
}
#[derive(Debug)]
enum Msg {
Increment,
Decrement,
}
#[derive(XeruneTemplate)]
#[template(source = r#"
<div style="flex-direction: column; align-items: center; justify-content: center; width: 100%; height: 100%;">
<span style="font-size: 24px;">Counter: {{ counter }}</span>
<div style="flex-direction: row; margin-top: 10px;">
<button onclick="Increment" style="padding: 5px 15px; margin: 5px;">+</button>
<button onclick="Decrement" style="padding: 5px 15px; margin: 5px;">-</button>
</div>
</div>
"#, ext = "html")]
impl Model for AppModel {
type Message = Msg;
fn update(&mut self, msg: Self::Message, _ctx: &mut Context) -> Option<Self::Message> {
match msg {
Msg::Increment => self.counter += 1,
Msg::Decrement => self.counter -= 1,
}
None
}
}Note: For best performance, please run all examples with the
--releaseflag.
cargo run --release --example music_player
cargo run --release --example todo
cargo run --release --example showcaseLicensed under the MIT License.


