oxiforge
YAML-to-Rust code generator for oxivgl LVGL 9.3 UIs.
Describe your UI in YAML, oxiforge generates safe Rust code that calls oxivgl
widget constructors at build time. Designed for no_std embedded targets
(ESP32, etc.) but works on any platform oxivgl supports.
Concept
You describe your UI as a YAML file — screens, widgets, styles, layouts.
During cargo build, oxiforge reads that YAML and generates Rust source
code that creates the UI through oxivgl,
a safe Rust binding layer for LVGL 9.3. The generated
code is pulled into your crate via include!(), so it compiles as part of
your application — no runtime YAML parsing, no interpreter overhead.
Under the hood, LVGL is a C library with its own object ownership: parents
own their children, and widgets store raw pointers to styles. oxiforge
bridges this gap by leaking style allocations (Box::leak) and forgetting
widget wrappers (core::mem::forget) so that LVGL's C object tree stays
intact while Rust's drop semantics don't interfere.
YAML format
A UI file has one top-level lvgl: key containing pages, style definitions,
gradients, and an optional theme.
lvgl:
default_font: montserrat_16
style_definitions:
- id: card
bg_color: 0x1E1E1E
radius: 8
pad_all: 10
pages:
- id: dashboard
bg_color: 0x121212
layout: flex
flex_flow: column
widgets:
- label:
text: "Battery: 13.8V"
styles: card
text_color: 0x4CAF50
- arc:
id: soc
width: 140
height: 140
min_value: 0.0
max_value: 100.0
value: 75.0
arc_width: 12
part_indicator:
arc_color: 0x4CAF50
Supported widgets
obj, label, button, switch, checkbox, slider, arc, bar,
dropdown, roller, scale, led, image, line
Layouts
- Flex —
layout: flex, withflex_flow,flex_align_main/cross/track,flex_grow - Grid —
layout: grid, withgrid_columns,grid_rows,grid_cellon children
Styles
- Inline — set properties directly on any widget
- Style definitions — reusable named batches, applied via
styles: nameorstyles: [a, b] - Theme — default styles per widget type
- State styles —
state_pressed:,state_checked:, etc. - Widget parts —
part_indicator:,part_knob:, etc.
Full property reference: docs/yaml-language-spec.md
Rust API
generate_from_str
Parse + validate + generate in memory. Returns generated Rust source as String.
let yaml = read_to_string.unwrap;
let code = generate_from_str.unwrap;
generate
Parse + validate + generate from file, write .rs to output directory.
Emits cargo::rerun-if-changed for build.rs use.
generate.unwrap;
Error reporting
Unknown YAML keys produce fuzzy "did you mean?" suggestions:
error: unknown property 'background_color'
hint: did you mean 'bg_color'?
Project integration
1. Add dependencies
# Cargo.toml
[]
= "0.1"
[]
= "0.1"
Working inside a checkout of this repository (e.g. the bundled examples)? Replace each line with
{ path = "../oxiforge" }/{ path = "../oxivgl" }as appropriate.
2. Create build.rs
3. Include generated code
// main.rs
extern crate alloc; // required for no_std targets
use *;
Each YAML page becomes a create_<page_id>(screen) call inside the
generated file.
Building for ESP32
See examples/arc_gauge/ for a minimal working example,
or examples/meter_view/ for a more substantial
alternator-regulator dashboard (arc + scale + mode pill + battery/engine/field
panels) ported from a real firmware screen.
License
oxiforge is licensed under GPL-3.0-only. This is a deliberate choice and has consequences worth understanding before you adopt it.
oxiforge runs as a build-dependency: it reads your YAML at build time and
emits Rust source that your crate include!()s. That generated source is then
compiled and linked into your binary. Under the GPL, code derived from a
GPL-licensed work is itself bound by the GPL — and the source oxiforge produces
qualifies as a derived work of oxiforge. The practical consequence is that a
crate which include!()s oxiforge-generated code, and the binary built from
it, must also be distributed under a GPL-compatible license.
This is intentional. If you want to ship a closed-source product that uses oxiforge, that license is not available off-the-shelf; please get in touch.
The runtime library oxiforge generates code against — oxivgl — is dual-licensed MIT OR Apache-2.0 and is unaffected by this. You can use oxivgl directly (writing widget code by hand) in a proprietary project without GPL obligations; only the YAML-to-Rust code path through oxiforge is GPL.