Structure a real application
Organize models, views, services, and platform edges without coupling your product to the renderer.
Split by responsibility
Keep the application model, its view composition, domain services, and platform adapters distinct. A practical starting point is app.rs for state and event routing, app/view.rs for Element construction, and focused service modules for external work.
src/
main.rs # target entry point
app.rs # state and event routing
app/view.rs # Element composition
services/ # domain I/O
theme.rs # product tokensKeep boundaries renderer-neutral
Domain services should return ordinary Rust values. The model decides when to launch work and how results change state. The view consumes state and returns Elements; it should not own network clients or platform windows.
Create child models for ownership
Use a child Entity when a feature needs independent state, tasks, subscriptions, lifecycle, or cached rendering. Use a plain view function when it only transforms inputs into elements.
Reference files
These are the implementation and guide files used for this chapter.
app_examples/fake-ai-harness/src/app.rsapp_examples/fake-ai-harness/src/app/view.rsdocs/repo/structure.mdA model, task, view, and virtual list working together
The Rust file below is imported verbatim by this page and compiled into the WebAssembly application running underneath it.
use argui::{
paint::{Border, CornerRadii},
runtime::{Context, Render},
text::{FontFamily, TextStyle},
ui::{Element, Sides, percent},
widgets::default_theme,
};
pub struct Example;
impl Render for Example {
fn render(&mut self, cx: &mut Context<Self>) -> Element {
let themes = default_theme(cx.environment());
let theme = themes.resolve(cx.environment().color_scheme);
let file = |name, purpose| {
Element::row([
Element::text(name).text_style(TextStyle {
family: FontFamily::Monospace,
color: theme.primary,
weight: 650,
..TextStyle::default()
}),
Element::text(purpose)
.text_style(TextStyle {
color: theme.muted_foreground,
..TextStyle::default()
})
.grow(1.0),
])
.gap(16.0)
.padding(Sides::length(14.0))
.background(theme.card)
.border(Border::all(1.0, theme.border))
.radius(CornerRadii::all(8.0))
};
Element::column([
file("main.rs", "target entry point"),
file("app.rs", "state and event routing"),
file("app/view.rs", "Element composition"),
file("services/", "domain I/O"),
])
.width(percent(1.0))
.padding(Sides::length(24.0))
.gap(9.0)
.background(theme.background)
}
}
Starting this lesson’s WebAssembly module…