# Stipple
[](https://github.com/KarpelesLab/stipple/actions/workflows/ci.yml)
[](https://crates.io/crates/stipple)
[](https://docs.rs/stipple)
[](LICENSE)
A cross-platform UI library and toolkit in Rust.
Stipple draws **beautiful, fully themeable** interfaces on Linux, macOS, Windows,
Android, iOS, and the web — **pixel-identical** across platforms under its own
themes, or **native** under `Theme::native()` — while depending on **as little
third-party code as possible**.
It builds on the pure-Rust [`oxideav`](https://github.com/OxideAV) media stack
for all 2D content rendering (scene graph, CPU rasterizer, font shaping, image
decode, SVG) and adds everything around it: native windowing and input per OS,
presenting the rendered buffer, and a declarative, reactive UI toolkit.
```rust
use stipple::prelude::*;
struct Counter { n: i64 }
fn view(state: &Counter, cx: &mut Cx<Counter>) -> Element {
let theme = *cx.theme();
column(vec![
heading(&theme, format!("{}", state.n)),
row(vec![
button_labeled(&theme, "−").on_tap(cx, |s: &mut Counter| s.n -= 1),
button_labeled(&theme, "+").on_tap(cx, |s: &mut Counter| s.n += 1),
])
.gap(8.0),
])
.gap(12.0)
.padding(Insets::uniform(24.0))
}
fn main() {
let mut app = App::new(Counter { n: 0 }, view)
.title("Counter")
.theme(Theme::dark());
if let Some(font) = Font::system_default() {
app = app.font(font);
}
app.run();
}
```
> **Status: pre-alpha.** The architecture and phased plan live in
> [`ROADMAP.md`](./ROADMAP.md). APIs are unstable.
The same app, rendered by Stipple's **native backends** and screenshotted in CI
(the `Visual` workflow) — Linux X11 (under Xvfb) and Wayland (under headless
sway), Win32, and Cocoa, each from-scratch with no windowing crates:
|  |  |  |  |
|  |  |
Input is verified too: CI synthesizes real events and screenshots the result —
X11 via `xdotool` (clicking a counter; caret-aware editing — type "Stipple",
arrow-left twice, insert "XY" → "StippXYle" with a mid-string caret), macOS via
`cliclick`, and **Wayland** via `wtype` (whose virtual keyboard exercises the
`wl_seat` keyboard + xkb-keymap decode path — Tab to focus, then type "stipple
wl"):
|  |  |  |  |
## Native look
`Theme::native()` follows the system's light/dark mode and accent color, and on
Windows, macOS and iOS has the OS's own UI framework draw the controls: `uxtheme`,
AppKit and UIKit, each rendering a control's chrome into a bitmap. Stipple keeps
layout, input, the caret and the labels. Linux has no native framework and Android's
needs the JVM, so controls stay self-drawn there, in the system's colors.
|  |  |  |  |
Windows has no switch and iOS has no checkbox or radio button, so those stay
self-drawn. The GPU backends can't draw these bitmaps yet, so `App::render_with`
skips the controls' chrome under this theme.
These screenshots, and the others on this page, are committed by CI after each
green push to `master`.
## Themeable by design
Every widget reads its colors and metrics from a [`Theme`] — a semantic
`Palette` (roles, interaction states, status colors, overlays), a `Typography`
scale, a `Spacing` scale, and a corner radius. Customizing is a one-liner:
`Theme::dark().with_accent(color).with_radius(14.0)` recolors the accent,
derives its hover/active tints, and picks a readable on-color automatically;
`high_contrast()` maximizes text/border contrast. **Material 3** is built in
too: `Theme::material3_light()` / `material3_dark()`, or
`Theme::material3_from_seed(color, dark)` for Material You dynamic color from
any seed. The same card below is rendered under four themes (light, dark, a
violet-accent dark, high-contrast), montaged in CI:

## Design at a glance
- **Software-first rendering**, with a GPU path: raw, hand-written GLES2
(SDF boxes + glyph atlas, usable for live windows via `App::render_with`),
Vulkan, Metal, Direct3D 11, and WebGPU backends. No wgpu.
- **Reactive / declarative** API: UI is a function of state. Frames are
damage-diffed and only changed regions are re-rasterized and presented.
- **Self-drawn widgets**: one theme engine, identical on every platform, unless
`Theme::native()` asks the OS to draw them.
- **High-DPI**: renders at the display's scale on every desktop backend and iOS.
- **Accessible**: the semantic tree is exposed to AT-SPI (Linux),
NSAccessibility (macOS) and UI Automation (Windows), each over a hand-written
bridge (D-Bus wire protocol, `objc_msgSend`, COM vtables).
- **No** `winit` / `wgpu` / `taffy` / `lyon` / GTK / Qt / `zbus` / `windows` /
`objc`. OS interfaces are hand-written per platform in `stipple::platform`.
## Modules
Stipple is one crate, `stipple`, with these modules:
| `stipple::geometry` | Logical-pixel math (Point, Size, Rect, Insets, Affine) |
| `stipple::render` | Scene → oxideav `VectorFrame` → raster → `Surface`; fonts |
| `stipple::platform` | Per-OS windowing, input, clipboard, file dialogs, accessibility bridges, shared memory + sandbox |
| `stipple::layout` | Flex/box layout solver |
| `stipple::core` | Reactive runtime: `View`, `Element` IR, reconcile, events, a11y tree |
| `stipple::anim` | Easing, tweens, springs |
| `stipple::style` | Design tokens and themes (incl. Material 3) |
| `stipple::widgets` | Standard widget library |
| `stipple::gpu` | Raw GPU backends, behind the `gpu` feature; dma-buf / shared-texture export. `gl`, `vk`, `d3d` and `mtl` enable GLES2, Vulkan, Direct3D 11 and Metal |
`App` and the prelude live at the crate root. The repository root is the
`stipple` crate; `examples/` holds the demo apps, and `docs/` the guides.
Widgets available in the prelude: `panel`, `row`, `column`, `spacer`,
`divider`, `label`, `heading`, `paragraph`, `button`, `button_labeled`,
`button_variant`, `text_field`, `text_editor`, `text_area`, `checkbox`,
`radio`, `switch`, `slider`, `progress_bar`, `spinner`, `swatch`,
`setting_row`, `tabs`, `scroll`, `menu` / `menu_item` / `open_menu`,
`open_dialog`, `tooltip`, `image` / `svg` (PNG, JPEG, GIF, WebP, BMP and SVG,
decoded by the oxideav stack; see [docs/images.md](./docs/images.md)), and
`viewport` (embedded external content).
## Examples
```sh
cargo run -p window # a settings panel in a native window
cargo run -p clickdemo # a click-counting button
cargo run -p calculator # a four-function calculator
cargo run -p textinput # an editable text field (Tab to focus, then type)
cargo run -p textarea # multi-line editing and selection
cargo run -p clipboarddemo # copy / cut / paste
cargo run -p scrolldemo # a clipped, wheel-scrolled list
cargo run -p overlaydemo # dropdown menu + modal dialog
cargo run -p tabsdemo # tabs + right-click context menu
cargo run -p hoverdemo # hover highlighting
cargo run -p motiondemo # shake, pulse, staggered list, interruptible spring
cargo run -p multiwindow # two OS windows sharing one state
cargo run -p filedialog # native file dialog (portal, IFileDialog, NSOpenPanel)
cargo run -p themegallery # one card under four themes (writes .raw files)
cargo run -p material3demo # Material 3 baseline + dynamic-color themes
cargo run -p imagedemo # PNG and SVG images, and the fit modes
cargo run -p bididemo # Hebrew, Arabic and mixed right-to-left text (--mirror: a mirrored UI)
```
Each opens a real native window via `App::run` (Wayland, then X11, on Linux;
Win32; Cocoa), or falls back to a one-shot headless render where no display is
available. Platform and subsystem probes live alongside them:
`gpuwindow` / `gpudemo` (GLES, `--features stipple/gl`), `d3ddemo`,
`metaldemo`, `dmabuftest`, `dri3probe`, `viewportdemo`, `contentproc`
(sandboxed content process composited over shared memory), `a11ydemo` and
`uiademo` (accessibility bridges), `androiddemo` (an Android app as a `NativeActivity` cdylib),
and `webdemo` (a `wasm32` module for a `<canvas>`). See [`docs/`](./docs/README.md)
for how to build and package each platform.
## Status & MSRV
Pre-alpha. The whole workspace builds on **Rust 1.88** (edition 2024).
Working today, each verified in CI on its platform:
- The reactive toolkit: layout, state, tap / keyboard / focus / drag / hover /
scroll / context menus, caret-aware multi-line text editing with selection,
word wrapping, clipboard, overlays, multi-window, and the widgets above.
- Native backends: **X11** (with MIT-SHM present), **Wayland**, **Win32**,
**Cocoa**, plus **web** (wasm + canvas), an **iOS UIKit** backend (run on the
simulator), and an **Android** `NativeActivity` backend with touch, keys,
timers and display-paced frames (driven on the emulator).
- **GPU**: GLES2 scene rendering in a live window, and off-screen Vulkan,
Metal, D3D11 and WebGPU pipelines.
- **Accessibility**: the full element tree on all three desktops.
- **Compositor seams** for embedding a sandboxed content process (e.g. a
browser engine): viewports, shared-memory and dma-buf / IOSurface / D3D
shared-handle buffer transport, input forwarding, seccomp sandboxing, and
DRI3 + Present on-window GPU present.
Next up (see `ROADMAP.md`): mobile touch input and full lifecycle, zero-copy
GPU swapchain present, accessibility change events, and broader toolkit depth.
## License
MIT