faststep
faststep is a UIKit-inspired UI framework for embedded Rust targets built on
embedded-graphics.
The crate is designed for projects where:
- the application should describe views and behavior, not raw touch bookkeeping
- the framework should own widgets, scrolling, alert presentation, and redraw flow
- device-specific display and touch code should stay behind traits
- the same UI layer should be able to target multiple OEM devices and, later, a simulator
This repository is preparing the first public 0.1.0 release. The goal of that
release is not to claim “finished framework”, but to publish a coherent and
documented foundation that is already useful in real device work.
What 0.1.0 Covers
The 0.1.x line is the first public foundation release for faststep.
It is intended to provide:
- a clear preferred architecture
- a documented public API
- compile-checked examples for each major widget family
- an explicit OEM or simulator boundary
- enough widget and container breadth for real UI composition
It intentionally does not try to hide that the framework will keep evolving.
The purpose of 0.1.0 is to release a sound base with good documentation, not
to wait until every future abstraction is settled.
Design Direction
The intended authoring flow is:
- Keep
mainthin. - Provide a root view implementation.
- Let an OEM adapter construct the board, display, and touch side.
- Start the system with
run_ui_system(...). - Let the root view configure its children and view metadata.
- Use container views for stack, tab, split, and alert behavior.
- Let controls keep their own interaction state.
- Build scrolling surfaces on top of
ScrollView. - Use datasource and delegate contracts for data-driven views such as lists.
That keeps responsibilities separated:
- app code owns structure and behavior
faststepowns framework mechanics- the OEM layer owns hardware and present policy
Main Concepts
Foundation
UiSystem: owns the display, root view, theme, i18n, and registration stateUiView: root or custom view contractViewRegistration: configuration object used duringconfigure(...)ViewEventandViewRedraw: explicit redraw and message flow
Runtime and OEM
DisplayPort: display backend abstractionUiCanvas: draw surface contract for overlays and dimmingUiRuntimeDriver: time, sleep, and touch polling abstractionUiRuntimePresenter: redraw batching and panel-specific presentation policyrun_ui_system(...): framework-owned runtime loop
Widgets and Containers
ButtonImageViewTextViewRichTextViewScrollViewListViewStackViewTabViewSplitViewAlertViewAlertHostModalHost
Shared Services
FsTheme: semantic palette configured once at startupI18n: lightweight localization layer
Why It Is Shaped This Way
The main engineering goal is to avoid two common failure modes in embedded UI projects:
- the UI loop lives in the application binary and becomes device-specific glue
- widget interaction state leaks upward into every screen and root view
faststep pushes against both:
- the runtime loop is owned by the framework
- buttons own their own press and highlight state
- alerts own their own modal timing and touch capture
- scrolling behavior is shared and centralized
- lists are driven by datasource and delegate roles instead of manual per-screen logic
This is the same reason the crate keeps a strong boundary between UI code and OEM-specific presentation code.
Typical Startup Shape
At a high level, a new app should look like this:
use Rgb565;
use ;
let display = new;
let theme = default
.with_accent
.with_status_colors;
let i18n = new;
let root = new;
let driver = new;
let presenter = new;
run_ui_system?;
The important part is not the exact syntax. The important part is the boundary:
- the application supplies the root view
- the framework runs the loop
- the OEM adapter owns hardware setup and present policy
View Authoring
Views are expected to declare their own metadata and child structure in
configure(...).
Typical responsibilities inside a view:
- set title
- set alpha or visibility
- enable clipping where appropriate
- register child views
- route touch into child widgets or containers
- return explicit redraw requests
Conceptually:
registration.set_title;
registration.set_clips_to_bounds;
registration.add_child?;
This is how faststep moves closer to a UIKit-style “view knows its structure”
model instead of a loose drawing helper model.
Scrolling and Lists
ScrollView is the shared scrolling primitive.
It owns:
- drag tracking
- inertial scrolling
- overscroll and snap-back behavior
- transient scroll indicator behavior
The scroll indicator is designed to behave like a mobile list:
- hidden on touch-down
- revealed only once real scrolling starts
- visible during drag, fling, or snap-back
- faded out after motion ends
ListView builds on top of ScrollView and adds:
- datasource-driven item identity and sizing
- delegate-driven row rendering
- row highlight state
- row selection state
Rows are rendered through ListRow and ListRowState, so a row renderer can
change appearance when highlighted or selected instead of carrying that logic as
parallel app state.
Alerts and Modal Presentation
Alerts are intended to be presentation-owned by faststep.
The application provides an alert spec:
let mut alerts = new;
alerts.present?;
The framework then owns:
- modal state
- backdrop fade
- panel motion
- touch capture
- dismissal timing
That is the correct long-term direction for API simplicity.
Theming
FsTheme is the global semantic palette for the system.
The default palette is light and neutral:
- whites and greys for structure
- blue for primary or confirm actions
- amber for warnings
- red for destructive or error actions
The theme is configured once at startup and then consumed semantically by views and widgets instead of each screen inventing its own raw color rules.
Examples Included In The Crate
The crate ships with compile-checked examples for the main API families:
- examples/buttons.rs
- examples/text_and_image.rs
- examples/scroll_and_list.rs
- examples/containers.rs
- examples/alerts.rs
- examples/runtime_shell.rs
- examples/uikit_root.rs
- examples/root_delegate.rs
These examples are intended to be docs.rs-friendly and are included in the packaged crate. The manifest enables example scraping so API pages can link back to real example code.
Documentation Set
The first release is documented from three angles:
- docs/DEVELOPER_GUIDE.md: architecture, authoring model, runtime boundary, and core contracts
- docs/WIDGET_CATALOG.md: quick map of the public widget and container surface
- examples/uikit_root.rs: end-to-end root view composition example
The docs.rs landing page is also backed by a dedicated crate overview in
docs/CRATE_DOCS.md so the published crate starts with more context than a
minimal API index.
Compatibility Position
UiApp is still exported because existing code depends on it, but it should be
treated as a compatibility layer rather than the preferred authoring surface.
New work should start from:
UiSystemUiViewViewRegistration- container views
- datasource and delegate-driven list APIs
Repository Rules
The repository keeps source files below the 250 LOC limit. When a module grows,
it should be split into a src/<module>/ folder instead of leaving one long
file behind. This release prep already applies that rule to the main framework
modules.
Current State
For the initial public release, the crate now has:
- release metadata
- crate-level rustdoc
- documented public API
- packaged examples
- a stricter module layout
- packaging verification
That is enough to keep preparing 0.1.0 deliberately instead of treating the
first release as an afterthought.