Skip to content
FernTech-EUPublic

About

Rust GUI framework

Resources

Contributing

Stars

22 stars

Watchers

0 watching

Forks

Repository files navigation

CI audit license

Teksilo

A pure-Rust, batteries-included GUI framework for desktop applications. Accessibility, internationalization, rich text, themes, persistent settings, drag-and-drop, charts, and a scene canvas all ship as first-class citizens.

Website: https://teksilo.rs

use teksilo::prelude::*;
use teksilo::widgets::Button;

fn main() {
    TeksiloAppBuilder::new()
        .theme(intui::light())
        .initial_window(
            WindowConfig::new()
                .title("Hello Teksilo")
                .size(400, 300)
                .root(|tree, _state| {
                    tree.add(
                        Button::new(lit!("Click Me"))
                            .on_activate_fn(|_ctx| println!("Clicked!")),
                    )
                }),
        )
        .run();
}

Add reactive state and derived bindings:

use teksilo::prelude::*;
use teksilo::widgets::{Button, TextWidget, VStack};

fn main() {
    TeksiloAppBuilder::new()
        .theme(intui::light())
        .initial_window(
            WindowConfig::new()
                .title("Counter")
                .size(300, 150)
                .root(|tree, _state| {
                    let count = Signal::new(0_i32);
                    let label = count.map(|n| format!("Count: {n}"));
                    tree.add(
                        VStack::new()
                            .spacing(12.0)
                            .child(TextWidget::new(lit!("")).text(label))
                            .child(
                                Button::new(lit!("Increment"))
                                    .on_activate_fn(move |_| {
                                        count.set(count.get() + 1)
                                    }),
                            ),
                    )
                }),
        )
        .run();
}

Real-world example

Skribisto, a rich-text writing tool built with Teksilo, was ported from C++/Qt to Rust/Teksilo. It is available here.

A widget catalog example is available if you run cargo run -p widget-catalog in the Teksilo repo. It shows most of the widgets. Dozens of runnable examples are available in the examples/ directory of the Teksilo repo.

Documentation

Available in docs/ and on https://docs.teksilo.rs.

Who is this for

Teksilo targets desktop applications with sustained keyboard use, rich text, localization, and assistive-technology support: editors, writing tools, consoles, and administration interfaces. It also provides individual controls for smaller applications.

The default light and dark themes follow JetBrains' Int UI. Accessibility and translation support are built into the widget APIs. Test the completed application against its users' needs and applicable requirements; toolkit features alone do not establish application conformance.

Design priorities

Teksilo is a retained-tree framework inspired by Qt and the SwiftUI layouting.

  • Composition with painting layered on top. The Widget trait offers both build() (compose children) and paint() (draw chrome); both methods are optional, and a single widget can do both. Most of the widgets are pure compositions of primitives (RectWidget, TextWidget, HStack, Padding); Card, Panel, overlays, and custom chrome layer paint on top of their composed children.
  • Accessibility at the trait level. Every widget declares its role and name in an accessibility() method that sits beside layout_response and paint. The AT tree is built alongside the widget tree, not reconstructed from it.
  • Compile-time-checked i18n. The tr! macro reads .ftl files at proc-macro expansion time and rejects missing keys, missing arguments, and unknown arguments at build time.
  • Rich-text stack as foundation. The document model, shaping, BiDi, color emoji, and undo/redo are the foundation, not a widget on top. Even the plain TextWidget routes through it.
  • Two API surfaces, one semantics. A fluent builder API for everything, plus an optional teksu! macro for SwiftUI-style declarative syntax. The macro desugars one-to-one to builder calls, so you can mix both in one file.

Status

Expect breaking changes between 0.x versions.

The test suite is roughly 9,400 tests in teksilo and over 12,000 across the whole stack. Tests target behavior (event dispatch, layout output, accessibility-tree structure), not implementation snapshots. The same widget tree runs under tests without a window, a GPU, or winit, and a simulated clock makes time-dependent behavior deterministic.

Teksilo builds on two earlier MPL-2.0 crates already at v1.x: text-document (rich-text document model) and text-typeset (typesetting engine).

The known gaps are listed at the end of this README.

Project. Architecture, design reviews, code review and final acceptance were human; code generation and routine refactoring were LLM-assisted (Claude Opus and Mistral Medium) under that review.

Scale: 40+ framework crates · 700k+ lines of Rust · 100+ widgets · 1600+ builder methods.

Roadmap to V1

The V1 API freeze is targeted for January 2027. Remaining milestones are a LiveImage widget for video, VM screens, and camera previews driven by another thread; validation on touchscreen and pen-capable hardware; and fixes from users' real-world applications beyond the maintainer's own use cases.

See Roadmap for the development retrospective and planned work. The V1 release date is not yet set.

Authorship and review

The rules under which Teksilo is built:

  1. Direct human communication is written by humans. PR messages, issues, posts, replies: no AI drafting, no AI polish. Common decency.

  2. Documentation may be drafted by AI; every line is reviewed by a human. API examples must compile against the current API. Claims are checked, not skimmed.

  3. Code, including tests, may be written by AI; every line is reviewed by a human. "Reviewed" means the reviewer understands the change well enough to defend it without the AI in the room. Blind vibe coding is forbidden. Plausible-looking code is not reviewed code.

  4. Architecture and public API are human. AI implements within them; it does not design them. The load-bearing surface is specified by a human: the Widget trait, Signal/Prop, the event model, anything downstream apps depend on.

  5. Authors and reviewers, both human, are the voluntary bottleneck. Final responsibility rests with them, not the AI. They may use any tool to help, AI included; what is missed lands on them regardless. They take their time; high-speed AI output is not a reason for high-speed work.

  6. The human who signs the work owns it, AI or not. Provenance is not disclosed in commits or PR text.

  7. No AI has ever been condemned by judges. Only humans and companies have. Stay sharp.

What's in the box (really, not a wishlist)

Widgets. Around 100 widgets: buttons, lists, tables, trees, tabs, menus, dialogs, popovers, file/color/date pickers, calendar, charts, wizard, breadcrumb, masonry layout, split button, custom title bar, and rich text editor. The widget-catalog example shows most of them, others are in dedicated examples.

Text. Full rich-text stack: document model with tables, lists, and undo/redo; typesetting engine with shaping, bidirectional text, color emoji, and zoom without reflow. Even the plain TextWidget routes through it, so every label gets correct shaping and font fallback.

Layout. SwiftUI-style two-phase negotiation: parents propose sizes, children respond, parents place. Spacers and stretch behave like ordinary widgets, with no special cases.

Reactive state. One Signal<T> type, used everywhere. A color change repaints; a size change relayouts; nothing rebuilds that doesn't need to.

Data models. ListModel<T> and TreeModel<T> are generic over your domain type and drive ListView, TreeView, TableView, TreeTableView, GridView, Repeater, and TabBar<T> directly. Sort/filter projections, per-view tree expand state, shared selection, drag-and-drop reorder, and descendant-to-ancestor tri-state checkbox aggregation come built in.

Rendering. GPU-accelerated via wgpu, with text and graphics sharing one pipeline. When nothing is moving, the app is idle: no wasted frames, near-zero CPU and GPU use.

Accessibility. Every widget declares its role and name through AccessKit at the trait level, and a per-widget override surface adjusts labels, descriptions, roles, relationships, and actions when the default isn't right. The default light and dark themes meet WCAG 2.1 AA contrast (CI-enforced), an opt-in high-contrast variant follows the OS "increase contrast" setting (re-queried on window focus), and conformance obligations attach to the shipped application.

Internationalization. Translations are checked at compile time via macro on top of Fluent: missing or misspelled keys are build errors. Right-to-left layout, locale-aware number and date formatting, and re-rendering on locale change are built in.

Themes. Default light and dark, inspired by JetBrains' Int UI; switching is instant and preserves focus, scroll position, and selection. Native mode adopts the live desktop colours: on Linux the active palette (accent, surface, selection, tooltip colors) follows the desktop environment (GNOME, KDE, Cinnamon) and is re-read when the desktop changes it, with the shapes still Int UI's (see docs/native-theme.md). The presets are a separate thing: Material 3, Fluent (Windows 11), macOS Aqua and KDE Plasma (Breeze) ship behind the theme-material3 / theme-fluent / theme-macos / theme-kde features, each with its own geometry and widget chrome, and the KDE preset also gives Native mode on a Breeze desktop Breeze's shapes through native_theme_kde(). Apps can override anything from a single color to a whole widget's chrome via the four-tier styling system (tokens → variants → recipes → style protocols), described in docs/styling-system.md.

Input. Keyboard shortcuts, menus, and accessibility actions flow through one rebindable pipeline; a user remap updates every surface that mentions the binding. External-source events (databases, file watchers) bypass it; widgets subscribe directly.

Async. Optional main-thread executor for imperative async/.await inside handlers: spawn_local for UI futures, spawn_blocking to offload work, and spawn_local_with to deliver a result with a fresh context. Off by default: the core stays synchronous and pays nothing; teksilo-tokio / teksilo-async-std add reactors for awaiting native runtime futures (timers, sockets, reqwest). For "data arrives, UI reacts," the reactive subscription path above stays simpler. See docs/async.md.

Tooltips. Three tiers from one system: plain text, rich (inline markup + shortcut hint + expandable detail), and composite (arbitrary widget body). Rich and composite tooltips become focusable on dwell.

Animations. Composable wrappers for the common cases (collapse, fade, slide, crossfade, blur, shake, pulse). The animation-owning wrappers honor the system "reduce motion" setting; the value-driven wrappers (Blur, Rotate) carry no motion of their own and delegate that gating to the caller's animate site (to_or_snap).

Drag and drop. Intra-app DnD with typed payloads, drop indicators, and edge auto-scroll. Cross-application (OS) DnD is supported in both directions: inbound drops and outbound app-to-OS export.

Persistent settings. Reactive K/V store and typed structs with migrations, atomic writes, and crash-safe quarantine of corrupt files. Automatic window-state restore with monitor-aware geometry sanitize.

Scene canvas. Pannable, zoomable viewport for non-grid content: story corkboards, mind maps, node-graph editors, simple maps. Heavyweight Widget nodes and lightweight SceneItems coexist under one transform, with accessibility APIs for both tiers.

Charts. BarChart, LineChart, and PieChart (with donut and center slot), generic over the app's data type. Pluggable axis-label formatters and theme integration are built in.

Docking. DockingLayout is a VS Code-style dockable layout: a fixed centre slot and four collapsible, splittable side regions, with an activity rail, drag-to-dock, per-corner ownership, a lock-down policy, and a serializable layout state to save and restore. See docs/docking.md.

Terminal. An embeddable Terminal widget runs a real shell over a pseudo-terminal (ConPTY on Windows, openpty on Linux and macOS), with VT emulation by alacritty_terminal and the view by Teksilo: colors, cursor, scrollback, selection, mouse reporting and Role::Terminal accessibility. It renders into the wgpu surface like any other widget. Off by default, behind the terminal feature. See docs/terminal.md.

Live pictures. LiveImage shows a picture another thread rewrites at display rate: a VM screen, a video, a camera preview. A commit uploads only what changed and repaints no widget, a window nobody can see does no work for it, and a texture is freed at the first frame that no longer draws it, so GPU memory stays flat. Input maps to the source pixel under it, and the automation tools aim at and read back the picture's pixels. See docs/live-image.md.

Web view (prototype). Embed HTML / web content as a WebView widget. It behaves like a normal widget: SwiftUI-style layout, dormancy-aware visibility (a page parked in a tab is hidden and stops rendering), JS↔Rust messaging, two-way URL binding, and Role::WebView accessibility. Still a prototype. The default engine is wry (macOS WKWebView / Windows WebView2 / Linux-X11 WebKitGTK) and is functional: its engines are native OS views composited on top of the window, and on Linux it needs the WebKitGTK toolkit and, on a Wayland session, XWayland. The Servo backend (the native Wayland path) renders offscreen into a picture the widget draws inside the window, so its page clips and sits under popovers like any other widget. The widget forwards pointer, touch, wheel and keyboard input to it, and mirrors its page's accessibility tree into the application's. See docs/web-view.md.

Widget previewer. Storybook-style 3-pane explorer (navigator, canvas, knob form) for the widget catalog, with live property editing, multi-variant rendering, and PNG export. Custom widget libraries register via inventory::submit! and become previewable with no extra wiring.

Tooling. In-app debug inspector (F12, debug builds only) with tabs for tree, properties, accessibility, theme, locale, focus, shortcuts, overlays, data models, and pointers. Opt-in privacy-conscious telemetry stack with compile-time-validated event schemas and a schema-drift linter (cargo teksilo-telemetry-lint).

Agent automation (MCP). A Model Context Protocol server lets an AI agent observe (the live accessibility tree plus screenshots) and drive (accessibility actions, synthetic pointer / key / IME input) a Teksilo app, in-process, with no OS accessibility layer needed. A debug-only bridge drives a live running app on Linux, Windows and macOS — a Unix-domain socket where the platform has one, a named pipe on Windows, and no surface at all in a release build — and the running app publishes an endpoint descriptor, so an agent attaches with --attach rather than a socket path scraped out of a log; a headless mode runs the toolkit's CI harness (and is a kit for building your own headless test harness: teksilo_automation::execute against your own tree). It reuses the same AccessKit tree every widget already declares: a node id is stable while the widget lives (re-find after a structural rebuild). Complements, rather than replaces, a real screen-reader smoke test. See docs/automation-mcp.md.

For depth on any of these, see docs/.

Getting started

cargo new my-app
cd my-app
cargo add teksilo

Tooling — cargo teksilo

Four things Teksilo relies on do not travel with the crate: the guides under docs/, the 56 worked examples (every one is publish = false), the agent skill, and the harness for driving a running app. That leaves anyone building with Teksilo — and any AI assistant helping them — working from less than the framework actually documents.

One install fixes it, and everything it answers is matched to the Teksilo version your Cargo.lock resolved:

cargo install cargo-teksilo
cargo teksilo init             # run inside your app
cargo teksilo symbol Button                  # exact public API, for your version
cargo teksilo symbol --crate data ListModel  # 32 crates are queryable
cargo teksilo search "make a list scrollable"
cargo teksilo probe install                  # automation harness -> scripts/

init installs the probe harness and instructions for detected agents. Use cargo teksilo init --agent codex --agent claude -y to select agents explicitly, even without existing configuration. cargo teksilo agent install cursor installs instructions only; agent list shows supported targets. User installation is cargo teksilo agent install claude --user (also supported for Vibe and opencode). Shared-file text outside the managed region is preserved; --force replaces conflicting generated files.

Search uses BM25 until you run cargo teksilo model fetch. No lookup command starts a model download. status --json and search --json provide structured output; --verbose adds diagnostics and --quiet suppresses informational text.

If ONNX Runtime will not build on your platform, cargo install cargo-teksilo --no-default-features gives the same tool with lexical search instead of hybrid; everything else is unchanged.

Full reference: docs/agent-tooling.md.

Running the demos

git clone https://github.com/ferntech-eu/teksilo
cd teksilo
cargo run -p simple-button      # the minimal app
cargo run -p widget-catalog     # browse every widget
cargo run -p file-dialogs       # native file dialogs

Inside a checkout, the extractor cargo teksilo symbol wraps is also directly available:

python3 tools/extract_widget_api.py --list
python3 tools/extract_widget_api.py button calendar tree_view

Development environment

Working on Teksilo itself needs nothing beyond a stable Rust toolchain and the system libraries winit, wgpu and arboard link against. text-document and text-typeset are ordinary crates.io dependencies, so a clone builds and tests straight away:

git clone https://github.com/ferntech-eu/teksilo
cd teksilo
cargo test --workspace

On Debian or Ubuntu the system libraries are:

sudo apt-get install --no-install-recommends \
  build-essential pkg-config \
  libglib2.0-dev libgtk-3-dev libsoup-3.0-dev \
  libwebkit2gtk-4.1-dev libjavascriptcoregtk-4.1-dev \
  libxkbcommon-dev libxkbcommon-x11-0 libwayland-dev libxcb1-dev libx11-dev

Building against local text-document / text-typeset

The two siblings are developed alongside Teksilo, and a change in one is usually made together with the change in the other. To build against local checkouts rather than the published versions, check them out beside this repository and create .cargo/config.toml:

# Local development overrides — NOT committed (see .gitignore).
#
# Cargo.toml declares `text-document` and `text-typeset` as ordinary crates.io
# dependencies, so a fresh clone and every CI job build without preparation.
# This file redirects them at the sibling checkouts so that edits there are
# picked up by the next `cargo build` here.
#
# Requires ../text-document and ../text-typeset beside this repository.
# Delete this file to build against the published versions instead.
[patch.crates-io]
text-document = { path = "../text-document/crates/public_api" }
text-typeset = { path = "../text-typeset" }

The layout it expects:

parent/
├── teksilo/          # this repository
├── text-document/
└── text-typeset/

That file is gitignored: it is per-machine, and keeping it out of the manifest is what lets CI and a fresh clone resolve the siblings from crates.io with no preparation step. When a sibling publishes a new version, bump the version in [workspace.dependencies] in Cargo.toml — the patch carries no version of its own, so a local build will not tell you that you are behind.

The committed Cargo.lock must resolve from crates.io without local patches. Building with the overrides above can add local package entries and remove registry checksums. Before committing a dependency change, run:

bash tools/relock-crates-io.sh

The script restores registry sources while preserving the tested versions. It fails if those versions cannot be resolved without the local checkouts. CI checks the committed lockfile with cargo metadata --locked.

teksilo-analytics-native is the exception to all of this. It is excluded from the workspace (it builds protobuf from source, which needs cmake and a C++ toolchain) and depends on teksilo-collector-proto, which is not published; that one keeps a plain path dependency on a sibling checkout. A default cargo build never reaches it.

Documentation

Reference documents live in docs/. Good entry points:

  • docs/architecture.md, overall design and gaps
  • docs/layout-primitives.md, the two-phase layout
  • docs/reactive-theme.md, themes, color tokens, OS color integration
  • docs/shortcut-intent-action.md, keyboard shortcuts and rebinding
  • docs/accessibility-overrides.md, per-widget AT customization
  • docs/idle-and-animation.md, idle discipline and the animation gates
  • docs/tooltips.md, docs/tab-widget.md, docs/title-bar.md, docs/drag-and-drop.md

Known gaps

  • CJK IME composition. Latin and BiDi input compose correctly; Chinese, Japanese, and Korean input methods need to be tested by actual users.
  • X11 verification breadth. The X11 custom title bar and drag-and-drop backends ship and are covered by protocol tests, but live verification has been done against KWin (via XWayland) and, in CI, Openbox. Other window managers are untested, and there is no run against a standalone Xorg server. A window manager without _NET_WM_MOVERESIZE is detected up front and keeps native decorations rather than producing an immovable window.
  • Mobile and web. Linux, Windows and macOS are the primary targets. No mobile or web targets. Web support is technically possible, but would lose accessibility, which is a core goal of the framework.
  • API stability. Pre-1.0; breaking changes are expected between minor versions. Yet, the biggest architecture changes of v0 are mostly settled, and the core concepts are unlikely to change drastically.

Architecture stack

Teksilo is part of a small stack:

  • text-document, the document model. Required dependency.
  • text-typeset, the typesetting engine. Required dependency.
  • Qleany, an architecture materializer that generates Clean Architecture (Vertical Slice variant) in Rust or C++/Qt from a YAML manifest. Independent and optional; pairs naturally with Teksilo for application backends.

Contributing

Bug reports and patches are welcome. Please open an issue before sending a non-trivial pull request so we can discuss whether the change fits.

  • The framework was built to support FernTech's application portfolio; roadmap priorities are weighted by what those applications need.
  • Architectural changes need a design discussion first. Surface-level changes (new builder methods, bug fixes, new examples) are easier.
  • Tests are required for new code. The suite runs headlessly, with no GPU or display server.
  • The teksu! macro and the builder API both need to keep working. New widgets should be usable from both.

No CLA. A DCO sign-off (git commit -s) on each commit is enough.

License

Mozilla Public License 2.0. See LICENSE. Teksilo can be used in commercial and closed-source software without restriction; modifications to the Teksilo files themselves must be shared under MPL2 if distributed; application code that merely uses Teksilo is under its own license.

Commercial support

For priority bug fixes, written support, or an indemnification agreement, contact support@ferntech.eu. For everyone else, the issue tracker is the right place.

Trademark

"Teksilo"™ is a trademark of FernTech, a French company, the subject of French trademark application No. 5292025 (INPI, classes 9 and 42; pending).

The MPL-2.0 source license does not grant trademark rights. Forks and derivative works may use the source code under MPL-2.0 but must adopt a distinct name and distinct branding when distributed (compare Firefox / Iceweasel, Chromium / Chrome).

Nominative use ("built with Teksilo", "Teksilo-compatible widget", articles describing Teksilo) is fine. Distribution packagers may keep the Teksilo name for packages that track upstream releases, including backported fixes, dependency adjustments, and build-system changes; see TRADEMARKS.md for where that line falls.

See TRADEMARKS.md for the full policy; for anything it doesn't cover, contact trademarks@ferntech.eu.

Acknowledgments

Teksilo builds on the work of others: AccessKit; winit and wgpu; HarfBuzz (via harfrust), swash, fontdb, etagere, and ICU4X; unicode-bidi; Fluent and the Mozilla l10n team; the published design notes of the Druid, Masonry, and Xilem projects; and SwiftUI's layout protocol. Anthropic and Mistral provided the language models whose code generation contributed substantially under human review.

The theme presets follow design languages published by others: JetBrains' Int UI, which the default light and dark themes are drawn from; Microsoft's Fluent and the WinUI theme resources; Google's Material 3; Apple's macOS Human Interface Guidelines; and the Breeze style of KDE Plasma. Each preset is an independent implementation, and none of those vendors or projects is affiliated with or endorses Teksilo. See TRADEMARKS.md and NOTICE.

About

Rust GUI framework

Resources

Contributing

Stars

22 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages