faststep 0.1.0

UIKit-inspired embedded UI framework built on embedded-graphics
Documentation
  • Coverage
  • 98.82%
    670 out of 678 items documented0 out of 0 items with examples
  • Size
  • Source code size: 257.13 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 45.97 MB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 2m 2s Average build duration of successful builds.
  • all releases: 2m 2s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • Homepage
  • bazyli/faststep
    3 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • bazyli

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:

  1. Keep main thin.
  2. Provide a root view implementation.
  3. Let an OEM adapter construct the board, display, and touch side.
  4. Start the system with run_ui_system(...).
  5. Let the root view configure its children and view metadata.
  6. Use container views for stack, tab, split, and alert behavior.
  7. Let controls keep their own interaction state.
  8. Build scrolling surfaces on top of ScrollView.
  9. Use datasource and delegate contracts for data-driven views such as lists.

That keeps responsibilities separated:

  • app code owns structure and behavior
  • faststep owns framework mechanics
  • the OEM layer owns hardware and present policy

Main Concepts

Foundation

  • UiSystem: owns the display, root view, theme, i18n, and registration state
  • UiView: root or custom view contract
  • ViewRegistration: configuration object used during configure(...)
  • ViewEvent and ViewRedraw: explicit redraw and message flow

Runtime and OEM

  • DisplayPort: display backend abstraction
  • UiCanvas: draw surface contract for overlays and dimming
  • UiRuntimeDriver: time, sleep, and touch polling abstraction
  • UiRuntimePresenter: redraw batching and panel-specific presentation policy
  • run_ui_system(...): framework-owned runtime loop

Widgets and Containers

  • Button
  • ImageView
  • TextView
  • RichTextView
  • ScrollView
  • ListView
  • StackView
  • TabView
  • SplitView
  • AlertView
  • AlertHost
  • ModalHost

Shared Services

  • FsTheme: semantic palette configured once at startup
  • I18n: lightweight localization layer

Why It Is Shaped This Way

The main engineering goal is to avoid two common failure modes in embedded UI projects:

  1. the UI loop lives in the application binary and becomes device-specific glue
  2. 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 embedded_graphics::pixelcolor::Rgb565;
use faststep::{FsTheme, I18n, run_ui_system};

let display = MyDisplayPort::new();
let theme = FsTheme::default()
    .with_accent(Rgb565::new(5, 24, 29), Rgb565::new(31, 63, 31))
    .with_status_colors(
        Rgb565::new(7, 40, 12),
        Rgb565::new(31, 43, 5),
        Rgb565::new(26, 13, 10),
        Rgb565::new(31, 63, 31),
    );
let i18n = I18n::new("en", "en", LOCALES);
let root = RootView::new();
let driver = MyRuntimeDriver::new();
let presenter = MyPresenter::new();

run_ui_system(display, root, theme, i18n, driver, presenter)?;

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(Localized::new("root.title", "Devices"));
registration.set_clips_to_bounds(true);
registration.add_child(
    ChildView::new(ViewId::DevicesList, list_frame).with_kind(ViewKind::List)
)?;

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 = AlertHost::<ScreenAlert, 2>::new();

alerts.present(
    ScreenAlert::DeleteConfirm,
    AlertSpec::confirm(
        Localized::new("delete.title", "Delete item?"),
        Localized::new("delete.body", "This action cannot be undone."),
    ),
)?;

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:

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:

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:

  • UiSystem
  • UiView
  • ViewRegistration
  • 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.