stipple 0.0.4

Stipple: a cross-platform, self-drawn UI toolkit in Rust.
Documentation
# Stipple

[![CI](https://github.com/KarpelesLab/stipple/actions/workflows/ci.yml/badge.svg)](https://github.com/KarpelesLab/stipple/actions/workflows/ci.yml)
[![crates.io](https://img.shields.io/crates/v/stipple.svg)](https://crates.io/crates/stipple)
[![docs.rs](https://img.shields.io/docsrs/stipple)](https://docs.rs/stipple)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](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:

| Linux / X11 | Linux / Wayland | Windows / Win32 | macOS / Cocoa |
|---|---|---|---|
| ![X11]./docs/screenshots/stipple-x11.png | ![Wayland]./docs/screenshots/stipple-wayland.png | ![Windows]./docs/screenshots/stipple-windows.png | ![macOS]./docs/screenshots/stipple-macos.png |

| Web / wasm + canvas | GPU / GLES (offscreen) |
|---|---|
| ![Web]./docs/screenshots/stipple-web.png | ![GPU]./docs/screenshots/stipple-gpu.png |

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"):

| X11 click | X11 edit (mid-string caret) | macOS click | Wayland type |
|---|---|---|---|
| ![clicks]./docs/screenshots/stipple-x11-clicks.png | ![typing]./docs/screenshots/stipple-x11-textinput.png | ![mac clicks]./docs/screenshots/stipple-macos-clicks.png | ![wl type]./docs/screenshots/stipple-wayland-input.png |

## 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 | macOS | iOS | Linux |
|---|---|---|---|
| ![Windows]./docs/screenshots/stipple-windows-native.png | ![macOS]./docs/screenshots/stipple-macos-native.png | ![iOS]./docs/screenshots/stipple-ios-native.png | ![Linux]./docs/screenshots/stipple-x11-native.png |

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:

![themes](./docs/screenshots/stipple-themes.png)

## 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:

| Module | Role |
|---|---|
| `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