The backends

On this page

xpui-backends

The two things that put xpui pixels on a panel, and the two helpers they need. A backend answers five traits — Canvas, TextMetrics, Chrome, InputSource, Clock — and the framework calls nothing else; in practice you write four, because Chrome comes from a macro, and the sixth trait a running screen needs, Navigator, is the application's. Which of the two backends you want depends on one question: does something already own your panel?

Which crate you want

No I have aDrawTargetYes a C++ firmwaredraws through FreeInkUIDoes somethingalready own your panel?embedded_graphicsdraws every pixelitselffuicalls that library overa C ABIxpui-chromepaints the componentsyour firmware'sown renderer
embedded_graphicsYou have a DrawTarget — a driver crate, a display over SPI, a simulator window. The backend draws every pixel itself, through xpui-chrome
fuiA C++ firmware already owns the screen and draws through FreeInkUI. This one calls that library over a C ABI, so a Rust screen comes out pixel-identical to a native one
screenshotA framebuffer and golden-image comparison, for testing what a backend actually painted. Host only
abi-checkParses a C header and the Rust that declares it and compares signatures. Two swapped parameters link fine — C has no mangling to disagree with — and the result is a corrupt call frame

docs/choosing-a-backend.md is the same choice at length, and what a third backend would need.

Using it

[dependencies]
xpui-embedded-graphics = { git = "https://github.com/XPUI-Framework/xpui-backends", branch = "main" }
# or
xpui-fui = { git = "https://github.com/XPUI-Framework/xpui-backends", branch = "main" }

[dev-dependencies]
xpui-screenshot = { git = "https://github.com/XPUI-Framework/xpui-backends", branch = "main", features = ["golden"] }

Both backends in one repository costs a consumer nothing: cargo resolves per crate, so a manifest naming xpui-fui compiles xpui-fui alone. The crates depend on xpui, and the embedded_graphics backend on xpui-chrome for its themed components. No boards crate, by design: a backend takes its measurements from whoever wires it and has no idea what a device is. Nothing is on crates.io yet, which is what the banner above is about.

Requirements

A Rust toolchain for everything but fui's C++ half, which needs two more things. clang-format 21 or newer is required: the gate's second stage fails without it, and refuses an older one rather than trusting it. The FreeInkUI headers are optional: the gate looks for them beside the checkout and at FREEINK_SDK_INCLUDE, and skips the shim's two stages with a note when it finds neither. docs/contributing.md says where it looks.

Checking it

./build-and-test.sh

The checks themselves are in xtask/ — this repository's own list, in Rust, holding nothing it does not run. ./build-and-test.sh fix formats in place first, Rust and C++ both. How a change is reviewed is in docs/contributing.md.

Where next

docs/choosing-a-backend.mdwhen embedded_graphics, when FreeInkUI, and what a third would need
docs/contributing.mdbuilding it, the gate, the five review steps, and how a commit is written
embedded_graphics/docs/design.mdmonochrome by design, the faces it ships, input, clipping, and type
embedded_graphics/docs/screenshots.mdpixel tests against a committed PNG, and why the first run fails
embedded_graphics/docs/hardware.mdwhat a parallel-bus panel taught: why PacedFill exists
fui/docs/design.mdwhy the FreeInkUI backend has the shape it does, the boundary, input, and the distinctions that break quietly
fui/docs/coverage.mdwhich FreeInkUI components the shim uses, and which it does not
fui/docs/firmware.mdadding the shim to a firmware: sources, includes, wiring, what the build does not ship

Where it sits

Every arrow is a dependency in a Cargo.toml, and they all point inward toward xpui, which depends on nothing at all. That is the rule the organisation is arranged around: a backend can be written without the framework knowing it exists, and a firmware reaches whatever it needs directly rather than through whoever happens to sit above it.

xpuithe frameworkxpui-chromecomponentsxpui-boardsseven devicesxpui-backendstwo backendsxpui-simulatora windowxpui-gallerythe appxpui-rp2040firmwarexpui-esp32firmwarexpui-cppa C++ hostxpui-devthe umbrella

Edit this page on GitHubIt lives in xpui-backends; a correction goes there.