Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
fret
[!WARNING] Experimental — under heavy development.
This project is an experiment in AI-driven software development. The vast majority of the code, tests, and documentation were written by AI (Codex). Humans direct architecture, priorities, and design decisions, but have not reviewed most of the code line-by-line. Treat this accordingly — there will be bugs, rough edges, and things that don't work. Use at your own risk.
Desktop-first, batteries-included entry points for building UI apps with Fret.
This is an ecosystem-level crate. It intentionally provides a small, ergonomic surface for
applications while keeping the framework/kernel crates (crates/*) policy-light.
Boundary note
fret is the golden-path authoring facade for application code. It is intentionally not the
repo's canonical example host.
- Use
docs/examples/README.mdfor the canonical learning/index path. - Keep runnable lessons in
apps/fret-cookbook/examples/, component coverage inapps/fret-ui-gallery, and heavier platform/app demos in their owning app crates.
This keeps the facade teachable while leaving example/tooling ownership outside the crate.
Editor/workspace-shell composition stays on owning crates such as fret-workspace instead of
growing the default fret facade into an editor-specific shell surface.
For repository overview / architecture docs, see the monorepo README: https://github.com/Latias94/fret
Quick start (in this repo)
If you are learning the repo's default path, follow this ladder in order:
hellosimple-todotodo
- Index:
docs/examples/README.md - The generated template READMEs repeat the same ladder and explain where each rung fits.
- Use
fretboard new todowhen you want the richer third-rung product baseline with explicit selector/query seams, not as a replacement for the first two rungs.
Generate a runnable starter (minimal baseline first):
Then move to the richer third rung when you actually want selectors + queries on top of a product baseline:
Keep the default authoring model intentionally small:
- use
LocalState<T>/LocalState<Vec<_>>for view-owned state, - use
local.layout_value(cx)/local.paint_value(cx)for ordinary LocalState reads, andlocal.layout_read_ref(cx, |value| ...)/local.paint_read_ref(cx, |value| ...)when a derived projection should avoid cloning the full slot, - keep one or two trivial locals inline; when a view owns several related
LocalState<T>slots, prefer a small*Localsbundle withnew(cx)and optionalbind_actions(&self, cx), then usecx.actions().locals_with((...)).on::<A>(...)for coordinated LocalState-first typed UI actions, - use
cx.actions().local(&local).set::<A>(...)/.update::<A>(...)/.toggle_bool::<A>()for single-local writes, - for view-owned keyed rows, bind payloads with
.action_payload(...), prefercx.actions().local(&rows_state).payload_update_if::<A>(...)as the default row-write path, - use
cx.actions().transient::<A>(...)when the real effect must happen with&mut Appinrender(), - drop to
cx.actions().models::<A>(...)only when coordinating sharedModel<T>graphs, - if you intentionally need the raw model handle itself, treat that as the advanced lane via
use fret::advanced::AppUiRawModelExt;+cx.raw_model::<T>(), - keep widget-local
.action(...)/.action_payload(...)/.listen(...)for activation-only surfaces that do not already expose a narrower widget-owned app-facing helper.
Quick start (Cargo)
With defaults (desktop + app):
[]
= { = "../fret" } # path is relative to your Cargo.toml
Enable selector/query helpers (optional):
[]
= { = "../fret", = ["state"] }
Enable the explicit router extension surface (optional):
[]
= { = "../fret", = ["router"] }
For editor-grade docking workflows, depend on fret-docking directly:
[]
= { = "../fret" }
= { = "../fret-docking" }
If your crate lives under apps/ in this repository:
[]
= { = "../../ecosystem/fret" }
Or explicitly opt into a smaller surface:
[]
= { = "../fret", = false, = ["desktop", "shadcn"] }
Minimal app skeleton
use *;
;
If app code needs explicit style/token nouns or icon helpers/IDs beyond the default lane, import
them from fret::style::{...} and fret::icons::{icon, IconId} instead of expecting them from
fret::app::prelude::*.
If app code needs explicit ThemeSnapshot, LocalState, or CommandId nouns for helper
signatures / command registration, import them intentionally from fret::style::ThemeSnapshot,
fret::app::LocalState, and fret::actions::CommandId.
If app code needs explicit semantic-role nouns, import them from
fret::semantics::SemanticsRole instead of expecting them from fret::app::prelude::*.
If app code needs explicit selector/query helper nouns beyond the grouped cx.data() story
(cx.data().query*(...), handle.read_layout(cx), cx.data().invalidate_query(...),
cx.data().invalidate_query_namespace(...)),
import them intentionally from fret::selector::ui::DepsBuilder,
fret::selector::DepsSignature, and
fret::query::{QueryError, QueryKey, QueryPolicy, QueryState, ...}.
For adaptive UI helpers such as breakpoints, safe-area insets, pointer/media preferences, or
Tailwind breakpoint probes, use fret::env::{...} explicitly.
For logical assets, use fret::assets::{...} and prefer AssetBundleId::app(...) /
AssetBundleId::package(...) plus AssetLocator::bundle(...) / register_bundle_entries(...);
keep AssetLocator::file(...) and AssetLocator::url(...) as capability-gated escape hatches.
For startup that needs one explicit development-vs-packaged decision, use
AssetStartupPlan + AssetStartupMode from fret::assets::{AssetStartupPlan, AssetStartupMode}
plus
FretApp::asset_startup(...) / UiAppBuilder::with_asset_startup(...): keep native/package-dev
inputs on development_dir(...) / development_manifest(...), and keep packaged/web/mobile-ready
bytes on packaged_entries(...), packaged_bundle_entries(...), or
packaged_embedded_entries(...). Generated modules still fit this packaged lane because they
already expose ENTRIES, bundle_id(), Bundle, install(app), and mount(builder). Keep
FileAssetManifestResolver::from_bundle_dir(...) /
FileAssetManifestResolver::from_manifest_path(...) plus
register_resolver(...) as the lower-level host-path escape hatch when app/bootstrap code
intentionally installs file-backed resolver layers directly instead of staying on the builder
startup contract.
When native/dev-only UI helpers still need file reload ergonomics, keep app/widget code on
logical bundle locators and let
fret-ui-assets::ui::ImageSourceElementContextExt::use_image_source_state_from_asset_request(...)
or fret-ui-assets::ui::SvgAssetElementContextExt::svg_source_state_from_asset_request(...)
consume the resolver's bundle/reference bridge instead of introducing direct raw file-path widget
loading. Keep resolve_image_source_from_host_locator(...) /
resolve_svg_source_from_host_locator(...) as the lower-level UI-ready source seams, and use
fret::assets::resolve_reference(...) / resolve_locator_reference(...) when a non-UI
integration truly needs the raw external reference itself.
On the app-facing builder path, prefer FretApp::asset_startup(...) /
UiAppBuilder::with_asset_startup(...) when startup needs one explicit
AssetStartupMode switch between development and packaged lanes, and layer additional packaged
overrides with FretApp::{asset_entries, bundle_asset_entries, embedded_asset_entries} or
UiAppBuilder::{with_bundle_asset_entries, with_embedded_asset_entries} when needed. On the host
path,
set_primary_resolver(...),
register_resolver(...), register_bundle_entries(...), and register_embedded_entries(...)
participate in one ordered resolver stack, so later registrations override earlier ones for the
same logical locator.
The same ordered builder surface now also includes compile-time/static entries through
FretApp::{asset_entries, bundle_asset_entries, embedded_asset_entries} and
UiAppBuilder::{with_bundle_asset_entries, with_embedded_asset_entries}.
Features
desktop: enable the native desktop stack (winit + wgpu) viafret-framework/native-wgpu.app: recommended baseline for apps (shadcn).state: enable selector/query helpers onAppUi(cx.data().selector_layout(...)for LocalState-first derived values, rawcx.data().selector(...)for explicit signatures, andcx.data().query(...)plushandle.read_layout(cx)for the default query read path, pluscx.data().invalidate_query(...)/cx.data().invalidate_query_namespace(...)for grouped app-lane query invalidation), plus the explicitfret::selector::*/fret::query::*secondary lanes when app code needs state helper nouns.router: enable the explicit app-level router surface (fret::router::{app::install, RouterUiStore, RouterOutlet, ...}).batteries: “works out of the box” opt-in bundle (config files + UI assets + icons + preloading + diagnostics).config-files: load layered config files from.fret/(settings/keymap/menubar).diagnostics: enable default diagnostics wiring (tracing + panic hook; plus extra dev tooling).tracing: advanced/maintainer alias for bootstrap tracing setup; preferfret-bootstrap/tracingdirectly for explicit wiring.devloop: advanced/maintainer alias forfret-launch/dev-state; prefer the owning crate directly when you need dev-state hooks.material3: discoverability alias only; depend onfret-ui-material3directly for Material 3 recipes and tokens.ui-ai: discoverability alias only; depend onfret-ui-aidirectly for AI-specific policy surfaces.ui-assets: enable UI render-asset caches (images/SVG) and install default budgets.icons: install the default built-in icon pack (Lucide).preload-icon-svgs: pre-register SVG icons on GPU ready.command-palette: enable the command palette wiring in the golden-path driver, including the default shadcn overlay bridge.
Design-system- or domain-specific ecosystems that do not form a stable fret root authoring
story should stay as direct crate dependencies instead of root feature proxies. The root
material3 / ui-ai feature names are retained only as discoverability aliases and do not pull
those crates into the fret publish closure.
Web / wasm
fret is desktop-first. For web demos in this repository, use tooling:
This runs apps/fret-demo-web via trunk serve.
Related workstream: docs/workstreams/fret-launch-app-surface-fearless-refactor-v1/
Choosing a native entry path
- App authors (default recommendation):
fret::FretApp::new(...).window(...).view::<V>()? - App authors with driver hooks:
fret::FretApp::new(...).window(...).view_with_hooks::<V>(...)? - Advanced integration with
fretdefaults:fret::advanced::run_native_with_fn_driver(...) - Advanced integration with
FnDriverhooks preserved:fret::advanced::run_native_with_fn_driver_with_hooks(...) - Advanced integration with a preconfigured
FnDriver:fret::advanced::run_native_with_configured_fn_driver(...) - Advanced low-level interop driver path (compat seam, non-default):
fret::advanced::interop::run_native_with_compat_driver(...) - Advanced low-level runtime/render/viewport seams:
fret::advanced::{kernel::*, interop::*}
If advanced/manual-assembly code also wants the ordinary component authoring vocabulary
(ui::*, .ui(), .into_element(...), model/overlay helper traits), import it explicitly with
use fret::component::prelude::*;. fret::advanced::prelude::* intentionally stays on the
advanced lane and no longer forwards the component prelude implicitly.
What remains first-class on fret
Advanced users do not need to drop to fret-launch immediately. The fret facade keeps the
following seams first-class:
FretApp::{setup(...), view::<V>(), view_with_hooks::<V>()}FretApp::asset_startup(...)plusfret::assets::{AssetStartupPlan, AssetStartupMode}FretApp::{asset_entries(...), bundle_asset_entries(...), embedded_asset_entries(...)}UiAppBuilder::{configure(...), setup(...), setup_with(...), with_asset_startup(...), with_bundle_asset_entries(...), with_embedded_asset_entries(...)}fret::assets::{FileAssetManifestResolver, register_resolver(...)}fret::advanced::FretAppAdvancedExt::install(...)fret::advanced::UiAppBuilderAdvancedExt::{install(...), on_gpu_ready(...), install_custom_effects(...)}UiAppDriver::{window_create_spec, window_created, before_close_window}UiAppDriver::{record_engine_frame, viewport_input, handle_global_command}fret::advanced::{kernel::*, interop::*}
The default builder chain stays small and app-facing on fret. Advanced users still keep the same
extension seams without dropping to fret-launch immediately, but the GPU/effects/bootstrap hooks
now live explicitly under fret::advanced instead of the default inherent builder surface.
Optional ecosystems also stay explicit. For example, the router integration lives under
fret::router; wire it with FretApp::setup(fret::router::app::install) instead of expecting it
to appear in fret::app::prelude::*. Docking and editor theming similarly stay on their owning
crates (fret-docking, fret-ui-editor) so advanced apps opt into those ecosystems explicitly
instead of learning extra fret root feature proxies. The default design-system surface is
similarly curated under
fret::shadcn: keep component names at shadcn::Button / shadcn::Card, use
shadcn::app::install(...) for app wiring plus environment-aware host-theme syncing,
shadcn::themes::apply_shadcn_new_york(...) for explicit one-shot/fixed presets, and
shadcn::raw::* only when you intentionally need the full underlying crate surface. Treat
shadcn::Button / shadcn::Card as the only first-contact component-family lane:
shadcn::app::* and shadcn::themes::* are setup lanes, not peer discovery lanes. Environment /
UiServices-boundary hooks stay off the curated lane: if you only depend on fret, reach them
through fret::shadcn::raw::advanced::*; if you depend on the recipe crate directly, use
fret_ui_shadcn::advanced::*. Reusable ecosystem bundles can share the same
.setup(...) seam by implementing
fret::integration::InstallIntoApp; ordinary app docs/examples should still teach plain installer
functions first. For small app-local composition, it is also acceptable to write
.setup((install_a, install_b)); prefer a named bundle type once that composition becomes
reusable or crate-facing API. Because Rust does not let a trait-bound-only fn(&mut App)
implementation accept plain function items without explicit casts, InstallIntoApp stays broad in
implementation. Treat that as an internal accommodation: keep .setup(...) on named installer
functions, tuples, or named bundles, and reserve .setup_with(...) for one-off inline closures or
runtime-captured values.
The same rule should apply to shipped resources: app-owned bytes normally live under
AssetBundleId::app(...), ecosystem/package-owned shipped bytes normally live under
AssetBundleId::package(...), and reusable crates should publish installer or mount helpers rather
than asking apps to mirror internal bundle registrations. Icon packs are still installed through
explicit crate::app::install seams backed by the global IconRegistry; reusable components
should prefer semantic IconId / ui.* ids instead of baking one vendor pack into their public
contract unless that dependency is intentionally explicit.
The same explicit-lane rule applies to optional state helpers: keep grouped
cx.data().selector_layout(...) as the default LocalState-first selector story, keep raw
cx.data().selector(...) for explicit shared Model<T> / global signatures, and keep
cx.data().query* plus handle.read_layout(cx) as the default query story. Import
DepsBuilder / QueryKey-style nouns from fret::selector::* / fret::query::* only when app
code actually needs to spell them.
Editor-themed apps should depend on fret-ui-editor directly and install the desired preset in
their own app setup. That keeps editor policy on the owning crate instead of teaching fret root
feature aliases for app-specific theme replay.
That makes fret suitable for both general-purpose desktop apps and many editor-style customizations
before you need to depend on fret-bootstrap or fret-launch directly.
When to drop down to fret-framework + fret-bootstrap
fret is designed to keep the “first app” and “small app” story simple. Prefer dropping down
to manual assembly when you need:
- a custom runner/event loop integration (
fret-launch), - non-default settings/keymap/config file layering,
- different icon/asset wiring policies than the kit defaults,
- experimenting with alternate component surfaces without the kit defaults.
Mapping (rough):
fret::UiAppBuilder->fret_bootstrap::UiAppBootstrapBuilderfret::UiAppDriver->fret_bootstrap::ui_app_driver::UiAppDriverfret::advanced::run_native_with_fn_driver(...)->fret_bootstrap::BootstrapBuilder::new_fn(...)fret::advanced::run_native_with_fn_driver_with_hooks(...)->fret_bootstrap::BootstrapBuilder::new_fn_with_hooks(...)fret::advanced::run_native_with_configured_fn_driver(...)->fret_bootstrap::BootstrapBuilder::new(...)with a preconfiguredFnDriverfret::advanced::interop::run_native_with_compat_driver(...)->fret_bootstrap::BootstrapBuilder::new(...)for advanced low-level interop / retained driver casesfret::advanced::kernel::*->fret-framework::*
The recommended manual-assembly entry point remains fret-bootstrap, keeping the underlying driver
hotpatch-friendly (function-pointer FnDriver surface, per ADR 0105 / 0110).