App structure
The generated command-line interface app and the checked-in examples follow the same broad structure.
Common files
A scaffolded app gives you:
src/app.rsfor the shared root widget and core product logic,src/main.rsfor the desktop entrypoint,src/lib.rsfor shared helpers used by mobile or web hosts,fission.tomlfor target metadata,platforms/<target>/for host packaging and launch scripts.
The examples keep a similar split even when they stay in a single crate.
Keep state and reducers close
A good first pass is:
- define
AppState, - define typed actions next to the state they change,
- bind reducers in
build()or through anActionRegistry, - use selectors for view-specific derived data.
This keeps code review focused on state transitions instead of callback wiring.
Inline binding vs central registration
Use ctx.bind(...) when the action is local to the widget tree.
Use ActionRegistry plus absorb_registry(...) when you want startup-time registration for global actions, like the inbox example does for capability-backed links.
Stable IDs are for runtime-owned behavior
Reach for explicit WidgetNodeIds when the runtime needs a durable identity across frames:
- animations,
- portal anchors,
- hero transitions,
- media/embed bookkeeping.
Do not assign IDs everywhere by default.
Prefer pure view models over build-time work
If a widget needs formatted text, booleans, or small derived slices of state, use a selector or helper struct instead of mutating state during build.
The counter example's selector-based CounterVM is the right level of indirection for many screens.