Tessera: UI Framework Designed with My Style in Mind

โš“ rust    ๐Ÿ“… 2025-06-16    ๐Ÿ‘ค surdeus    ๐Ÿ‘๏ธ 3      

surdeus

Hello everyone,

I'd like to introduce a project I'm working on: Tessera , an immediate-mode GUI framework for Rust. The project is still in its early stages (WIP), but the core design has solidified enough that I would appreciate some early feedback from the community.

The source code is available here: shadow3aaa/tessera on github

To see the current state of the project, the best place to look is the example crate.

The Core Philosophy: "GUI is not special"

The design principle behind Tessera is that UI code shouldn't require a special, complex object model that is separate from the rest of an application's logic. Instead, a UI component should simply be another function in your program.

This means developers don't need to implement struct Component or manage complex lifecycle hooks. In Tessera, a component is just a function annotated with a macro.

A Quick Glance

Hereโ€™s a small example to give you a feel for the API. This component displays a click counter from shared application data.

#[tessera]
fn value_display(app_data: Arc<AppData>) {
    // surface is a basic component that provides a colored, rounded rectangle surface
    surface(
        SurfaceArgsBuilder::default()
            .corner_radius(25.0)
            .color([0.9, 0.8, 0.8, 1.0]) // Light red fill, RGBA
            .build()
            .unwrap(),
        move || {
            // text is a child component that renders text
            text(
                app_data
                    .click_count
                    .load(atomic::Ordering::SeqCst)
                    .to_string(),
            );
        },
    )
}

Core Concepts

The framework is built around a few core concepts:

1. Function-Based Components:
All components are functions annotated with the #[tessera] macro. This macro handles the boilerplate of integrating the function into the component tree. Components can accept arguments and take other components as FnOnce() children.

2. Stateless by Default:
Components themselves don't hold state. State is managed externally (typically via Arc, atomics, or other shared state patterns) and passed into components as arguments. This helps keep the UI logic clean.

3. Explicit Layout and State Handling (When Needed):
For simple containers, the framework provides default layout behavior. For more complex components, you can provide closures to define custom logic. Here is a conceptual example showing the full structure of a component, which clearly separates layout, child component construction, and event handling:

use tessera_macros::tessera;

#[tessera]
pub fn my_component(
    // Parameters, like state, styling, children
    child: impl FnOnce(), // For components that accept children
) {
    // Optional: Define custom layout logic
    measure(Box::new(move |input| {
        // Calculate size, position children, set drawable
        // This runs during the measure pass
        Ok(ComputedData { width, height })
    }));

    // Required: Execute child components (if any)
    child(); // This builds the component tree

    // Optional: Handle user interactions and events
    state_handler(Box::new(move |input| {
        // Respond to clicks, keyboard, scroll events
        // This runs every frame after the measure pass
    }));
}

What I'm Looking For

I welcome feedback on any aspect of the project. I am particularly interested in your thoughts on the following:

  1. API Design & Ergonomics: Is the #[tessera] macro and the function-based component model intuitive? Are the measure and state_handler APIs clear?

  2. General Code Review: Any feedback on idiomatic Rust usage, architectural decisions (the project is a multi-crate workspace), potential performance issues, or anything else you notice would be very helpful.

Thank you for your time. I look forward to your thoughts and suggestions.

1 post - 1 participant

Read full topic

๐Ÿท๏ธ rust_feed