RepoPilotOpen in app →

linebender/druid

A data-first Rust-native UI design toolkit.

Healthy

Healthy across the board

weakest axis
Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 2w ago
  • 35+ active contributors
  • Apache-2.0 licensed
Show all 6 evidence items →
  • CI configured
  • Tests present
  • Concentrated ownership — top contributor handles 50% of recent commits

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/linebender/druid)](https://repopilot.app/r/linebender/druid)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/linebender/druid on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: linebender/druid

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/linebender/druid shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across the board

  • Last commit 2w ago
  • 35+ active contributors
  • Apache-2.0 licensed
  • CI configured
  • Tests present
  • ⚠ Concentrated ownership — top contributor handles 50% of recent commits

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live linebender/druid repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/linebender/druid.

What it runs against: a local clone of linebender/druid — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in linebender/druid | Confirms the artifact applies here, not a fork | | 2 | License is still Apache-2.0 | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 45 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>linebender/druid</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of linebender/druid. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/linebender/druid.git
#   cd druid
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of linebender/druid and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "linebender/druid(\\.git)?\\b" \\
  && ok "origin remote is linebender/druid" \\
  || miss "origin remote is not linebender/druid (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(Apache-2\\.0)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"Apache-2\\.0\"" package.json 2>/dev/null) \\
  && ok "license is Apache-2.0" \\
  || miss "license drift — was Apache-2.0 at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "druid/src/lib.rs" \\
  && ok "druid/src/lib.rs" \\
  || miss "missing critical file: druid/src/lib.rs"
test -f "druid-shell/src/application.rs" \\
  && ok "druid-shell/src/application.rs" \\
  || miss "missing critical file: druid-shell/src/application.rs"
test -f "druid-derive/src/lib.rs" \\
  && ok "druid-derive/src/lib.rs" \\
  || miss "missing critical file: druid-derive/src/lib.rs"
test -f "Cargo.toml" \\
  && ok "Cargo.toml" \\
  || miss "missing critical file: Cargo.toml"
test -f "docs/src/SUMMARY.md" \\
  && ok "docs/src/SUMMARY.md" \\
  || miss "missing critical file: docs/src/SUMMARY.md"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 45 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~15d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/linebender/druid"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

Druid is a data-first Rust-native UI toolkit that prioritizes performance and native platform integration for building desktop applications. It provides a widget library (Button, Flex, Label, etc. in druid/src/widget/) with declarative UI composition and reactive data binding through a lens-based architecture (druid-derive macros). The core innovation is its data-first philosophy where UI state flows through strongly-typed Rust data structures rather than imperative mutations. Workspace monorepo with 4 primary crates: druid/ (main UI framework, ~2.3M LOC), druid-shell/ (platform abstraction layer), druid-derive/ (procedural macros for Data and Lens derive), and docs/book_examples/ (runnable tutorials). Architecture: UI widgets compose via druid::widget::{Flex, Button, Label}; state flows through immutable Data types bound via Lens to widgets; platform code isolated in druid-shell/.

👥Who it's for

Rust developers building desktop UI applications who want type-safe, performant GUIs with native platform look-and-feel. Specifically: systems programmers and Rust enthusiasts who value correctness over rapid prototyping, and those who need resolution-independent UI (see docs/src/07_resolution_independence.md).

🌱Maturity & risk

UNMAINTAINED/ABANDONED. The project explicitly states in README: 'The Druid project has been discontinued.' Development moved to Xilem successor project. While Druid has significant testing history and periodic crates.io releases, there are zero new features or bug fixes. The CI/CD is disabled (evidenced by workflows in .github/workflows but no active maintenance signals). Not production-ready for new projects.

CRITICAL RISK: Project is officially discontinued with no maintenance. Dependency updates will stall (Cargo.lock exists but unmaintained). Single-point failure: Linebender org controls all future security patches. Breaking changes in Rust/platform APIs will not be addressed. Active bloat.yml CI suggests historical concern for binary size, but this is now a warning sign of abandonment rather than active optimization. Using this in production means accepting permanent technical debt.

Active areas of work

NOTHING. Project is frozen. No active development, no pending PRs, no milestone work. Last visible activity is historical: CHANGELOG.md and docs/ are complete but static. The druid-derive tests (druid-derive/tests/) and widget examples (docs/book_examples/src/) represent the final working state.

🚀Get running

Clone and build (for historical reference only): git clone https://github.com/linebender/druid.git && cd druid && cargo build. Run example: cargo run --example getting_started. See docs/src/02_getting_started.md for tutorial. WARNING: Do not use for new projects—use Xilem instead.

Daily commands: Development: cargo build --workspace builds all crates. Run example app: cargo run --example hello_web or cargo run --example getting_started. Run tests: cargo test --workspace. Generate docs: cargo doc --open. Clippy lint enforced via clippy.toml.

🗺️Map of the codebase

  • druid/src/lib.rs — Main entry point and public API surface; defines core traits (Widget, Data, Lens) and application initialization patterns.
  • druid-shell/src/application.rs — Platform abstraction layer for window management and event loop; essential for understanding cross-platform backend delegation.
  • druid-derive/src/lib.rs — Procedural macro implementation for Data and Lens derives; foundational to the data-first paradigm that defines Druid's architecture.
  • Cargo.toml — Workspace configuration defining three core crates (druid, druid-shell, druid-derive) and their dependency relationships.
  • docs/src/SUMMARY.md — Documentation roadmap covering core concepts: data binding, widgets, lenses, and environment; essential context for feature design.
  • druid-shell/src/backend/mod.rs — Backend abstraction facade routing to platform-specific implementations (GTK, macOS, Wayland); critical for understanding platform support.
  • CHANGELOG.md — Comprehensive release history documenting design decisions, breaking changes, and architectural evolution across versions.

🛠️How to make changes

Add a Custom Widget

  1. Create a new struct implementing the Widget trait in a new module under druid/src/widget/ (druid/src/widget/my_widget.rs)
  2. Implement event(), lifecycle(), update(), layout(), paint() and size_hint() methods to define behavior and rendering (druid/src/widget/my_widget.rs)
  3. Export the widget from druid/src/widget/mod.rs with pub use (druid/src/widget/mod.rs)
  4. Create a runnable example demonstrating the widget in docs/book_examples/src/custom_widgets_md.rs (docs/book_examples/src/custom_widgets_md.rs)

Derive Data & Lens for a Custom Type

  1. Add #[derive(Data, Lens)] to your struct definition with optional #[data(ignore)] for non-data fields (your_app.rs)
  2. Ensure all fields either implement Data or are annotated #[data(ignore)]; the macro generates PartialEq and Clone implementations (your_app.rs)
  3. Use the auto-generated Lens implementations to bind widget state to struct fields, e.g., TextBox::new().lens(MyData::my_field) (your_app.rs)
  4. Reference druid-derive/tests/ for attribute patterns like #[lens(ignore)] and generics handling (druid-derive/tests/with_lens.rs)

Add Platform-Specific Backend Support

  1. Create a new platform module under druid-shell/src/backend/ (e.g., druid-shell/src/backend/wayland/) (druid-shell/src/backend/wayland/mod.rs)
  2. Implement the backend trait methods (Application, Window, Clipboard, Dialog) matching the GTK/macOS interface signatures (druid-shell/src/backend/wayland/application.rs)
  3. Register the backend in druid-shell/src/backend/mod.rs with a conditional feature flag (e.g., #[cfg(feature = 'wayland')]) (druid-shell/src/backend/mod.rs)
  4. Add Cargo feature to druid-shell/Cargo.toml and document in druid-shell/README.md (druid-shell/Cargo.toml)

🔧Why these technologies

  • Rust with lifetime & type system — Enforces memory safety and immutable-by-default data patterns; enables fearless concurrent UI updates via Data trait
  • Procedural macros (syn/quote) — Eliminates boilerplate for Data/Lens derives; codegen ensures consistency and reduces runtime overhead
  • Platform-specific backends (GTK, AppKit, Wayland) — Achieves native look-and-feel on each platform while sharing core widget logic; isolates platform drift
  • Lens pattern (functional optics) — Provides type-safe, composable access to nested state; decouples widget logic from data hierarchy
  • Workspace structure (3 crates) — Separates concerns: druid (logic), druid-shell (platform), druid-derive (codegen); enables independent versioning and reuse

⚖️Trade-offs already made

  • Data-first reactive model with immutable updates

    • Why: Prevents bugs from shared mutable state; simplifies reasoning about UI consistency
    • Consequence: Higher allocation overhead per frame; requires explicit lens-based state projection; learning curve for FP concepts
  • Platform-specific backends instead of unified graphics layer

    • Why: Achieves native platform semantics and performance; avoids thin abstraction leaks
    • Consequence: 3× more code to support GTK/macOS/Wayland; maintenance burden for each platform; harder to add experimental platforms
  • Manual event/lifecycle callbacks instead of declarative markup

    • Why: Flexible imperative control; easier to express complex conditional logic
    • Consequence: Verbose widget definitions; no compile-time validation of event handlers; less familiar to web developers
  • Compile-time macro derives instead of runtime reflection

    • Why: Zero-cost abstractions; early error detection; no runtime metadata overhead
    • Consequence: Macros are complex (hard to debug); limited runtime flexibility; requires proc-macro knowledge for extensions

🚫Non-goals (don't propose these)

  • Not a web framework—renders only to native windows via platform APIs (no browser/HTML output)
  • Not suitable for real-time 3D graphics—focused on 2D UI widgets, not game engines
  • Not a layout-only library—tightly coupled to event handling and widget lifecycle
  • Not intended for mobile platforms—only supports desktop (Linux/macOS); no iOS/Android support
  • Project is discontinued and unmaintained; new development is in Xilem (successor project)

🪤Traps & gotchas

  1. Project is officially abandoned—CI will not block PRs, security issues won't be patched. 2) druid-derive uses proc_macro which requires nightly or pinned stable Rust (check Cargo.toml for MSRV). 3) Platform abstraction (druid-shell) has X11/Wayland/Windows/Cocoa backends with platform-specific bugs that won't be fixed. 4) Localization uses Fluent (.ftl files) which is non-standard in Rust ecosystem; see docs/src/06_env.md for configuration. 5) Resolution independence is baked into rendering (see docs/src/07_resolution_independence.md); hardcoded pixel values will break on high-DPI displays. 6) druid/examples/web/ requires wasm-pack (see Cargo.toml); not all widgets support web target.

🏗️Architecture

💡Concepts to learn

  • Lens (optics-based data access) — Lenses are Druid's unique architectural pattern for composable, type-safe selection of nested data in immutable structs; understanding Lens::get/put is essential to building Druid apps without cloning the entire state tree
  • Data trait and immutable state flow — Druid's reactive model requires app state to implement Data (a sealed trait enforcing structural equality and immutability); any mutation requires cloning the entire data structure, which is a radical design choice vs. mutable OOP UI frameworks
  • Widget trait and composition — Every UI element implements the Widget<T> trait (event/lifecycle/paint methods); widgets are functional composers (Flex, Container) rather than imperative DOM manipulators, enabling predictable rendering and layout
  • WidgetExt trait and builder pattern — WidgetExt adds fluent methods (.padding(), .center(), .on_click()) to any Widget; this enables declarative composition without nested constructor calls, directly visible in examples/getting_started.rs
  • Localization via Fluent and LocalizedString — Druid uses Mozilla's Fluent format (.ftl files) for i18n rather than gettext/PO files; LocalizedString with dynamic arguments (see docs/src/06_env.md) enables locale-aware label text, a non-obvious pattern
  • Platform abstraction layer (druid-shell) — Druid decouples UI logic from OS-specific windowing/event handling via druid-shell crate; understanding this split is critical for platform-specific bug fixes or porting to new platforms
  • Procedural macros for boilerplate reduction — druid-derive crate provides #[derive(Data)] and #[derive(Lens)] macros to auto-generate trait impls; understanding syn/quote metaprogramming is essential for extending Druid or debugging macro errors
  • linebender/xilem — Official successor to Druid with fundamental architecture improvements; any new Rust UI work should use Xilem instead
  • DioxusLabs/dioxus — Alternative Rust-native UI toolkit using React-like component model; comparable goal of ergonomic declarative UIs with strong typing
  • iced-rs/iced — Elm-inspired Rust UI framework with data-first design philosophy; closest architectural peer to Druid's approach, still actively maintained
  • gtk-rs/gtk4-rs — Rust bindings for GTK4; lower-level platform abstraction alternative used when Druid-like high-level toolkit is unavailable

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive UI tests for druid-derive macro edge cases

The druid-derive crate has UI tests in druid-derive/tests/ui/ with several .stderr files documenting expected compiler errors, but coverage appears incomplete. Missing test cases for common derive macro mistakes (e.g., conflicting lens attributes, invalid field types, nested generic constraints) would catch regressions early and provide better error messages to users.

  • [ ] Review existing druid-derive/tests/ui/*.rs and *.stderr files to identify test gaps
  • [ ] Create 3-5 new UI test files in druid-derive/tests/ui/ for uncovered error scenarios (e.g., invalid attribute combinations, unsupported struct variants)
  • [ ] Generate corresponding .stderr files by running cargo test --test ui and capturing expected compiler output
  • [ ] Document the new test cases in druid-derive/README.md with examples of what errors they catch

Add missing CI workflow for book examples compilation and verification

The docs/book_examples/ directory contains Cargo.toml and multiple example files used in documentation, but there's no dedicated GitHub Actions workflow to verify these examples compile correctly. This is critical since broken documentation examples harm user onboarding. The existing .github/workflows/ci.yml may not explicitly test book examples.

  • [ ] Examine .github/workflows/ci.yml to confirm it doesn't currently test docs/book_examples
  • [ ] Create a new workflow file .github/workflows/book-examples.yml that runs cargo check and cargo build on docs/book_examples
  • [ ] Add a step to verify each example file in docs/book_examples/src/ can be compiled independently
  • [ ] Link the workflow to run on push to docs/ directory and PR changes to maintain book example validity

Add platform-specific integration tests for druid-shell examples

The druid-shell crate has several examples (shello.rs, edit_text.rs, invalidate.rs, perftest.rs, quit.rs) but no automated tests verifying they can at least initialize and run basic operations. Adding CI checks to compile and optionally run headless validation of these examples would catch platform-specific regressions early.

  • [ ] Review druid-shell/examples/*.rs to understand what each example does and its dependencies
  • [ ] Create druid-shell/tests/examples_compile.rs that uses cargo_metadata or similar to verify all examples in druid-shell/examples/ compile without errors
  • [ ] Add a GitHub Actions step in .github/workflows/ci.yml to run cargo build --examples for druid-shell with platform-specific conditions (linux, macos, windows)
  • [ ] Document in druid-shell/README.md which examples are recommended for testing platform-specific behavior

🌿Good first issues

  • Audit druid-derive/tests/ui/*.stderr files against current compiler messages—UI test fixtures (e.g., with-empty-struct.stderr, with-enum.rs) likely have bitrotted error format strings that no longer match actual proc_macro diagnostics.: low: fixes flaky test suite
  • druid/examples/ has 20+ example apps but docs/SUMMARY.md doesn't reference them all—create a gallery section in book_examples/src/ that lists all examples with one-line descriptions and links to source.: low: improves discoverability for learning; historical archive value
  • druid-shell has platform-specific code paths for X11/Windows/Cocoa but no integration tests verifying platform abstraction contract (e.g., WindowBuilder::build() behavior across all three). Add minimal snapshot tests in druid-shell/tests/ that verify consistency.: medium: documents current behavior for preservation; catches regressions in any future maintenance fork

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 0f8b119 — Bump rand from 0.8.5 to 0.8.6 (#2426) (dependabot[bot])
  • 5ac72d6 — Bump time from 0.3.44 to 0.3.47 (#2424) (dependabot[bot])
  • b27ea6a — Add Cargo.lock and upgrade dependencies. (#2423) (xStrom)
  • 3638264 — Fix GitHub Pages deployment. (#2422) (xStrom)
  • bbd0154 — Update stable Rust to 1.92 and satisfy Clippy. (#2421) (xStrom)
  • e8d0837 — Update Piet to v0.7.0-cairo18. (#2410) (xStrom)
  • b831b5f — Remove deprecated text::format export. (#2413) (xStrom)
  • 55e2dd8 — Update documentation to reflect the discontinuation. (#2412) (xStrom)
  • 7ecc790 — Update SemVer compatible dependencies. (#2411) (xStrom)
  • 49b5352 — Update Rust stable to 1.82 and satisfy Clippy. (#2409) (xStrom)

🔒Security observations

The Druid UI toolkit codebase shows a reasonable security posture based on structural analysis. It is a Rust project which provides memory safety guarantees. Key observations: (1) No hardcoded secrets, credentials, or API keys detected in file structure; (2) No obvious SQL injection or XSS risks given the UI toolkit nature (not a web framework); (3) No exposed configuration issues visible; (4) No Docker infrastructure provided for analysis. The main security concerns are: (1) incomplete dependency visibility in the provided files—requires running 'cargo audit' and checking actual Cargo.lock; (2) native platform backend complexity (GTK, macOS) which requires additional security review; (3) clipboard operations which handle potentially sensitive user data; (4) code generation via macros which needs thorough validation. The project appears well-maintained with CI/CD workflows, proper licensing, and contribution guidelines. Recommend: perform full dependency audit, conduct security review of FFI boundaries, and test clipboard data handling.

  • Low · Incomplete Dependency Information — Cargo.toml, druid/Cargo.toml, druid-shell/Cargo.toml, druid-derive/Cargo.toml. The provided Cargo.toml (workspace root) does not show the actual dependencies for the crates. Direct examination of individual crate dependency files (druid/Cargo.toml, druid-shell/Cargo.toml, druid-derive/Cargo.toml) is required to assess for vulnerable dependencies. Without seeing the full dependency tree, potential supply chain vulnerabilities cannot be evaluated. Fix: Review actual dependency versions against the RustSec advisory database (https://rustsec.org/). Run 'cargo audit' to identify any known vulnerabilities in dependencies. Pin dependency versions appropriately and maintain regular update cycles.
  • Low · Native Code Backend Complexity — druid-shell/src/backend/gtk, druid-shell/src/backend/mac. The project includes platform-specific backends (GTK, macOS, likely Windows) with native code integration through FFI. This increases the attack surface for memory safety issues, especially in druid-shell which contains low-level window management and clipboard operations. Fix: Conduct regular security audits of FFI code. Use tools like 'cargo clippy' and 'cargo audit' with FFI-specific checks. Validate all data crossing FFI boundaries. Consider using higher-level safe abstractions where possible.
  • Low · Clipboard Access Potentially Sensitive — druid-shell/src/backend/gtk/clipboard.rs, druid-shell/src/backend/mac/clipboard.rs. Clipboard operations in cross-platform backends (GTK, macOS) may expose sensitive data if not properly handled. User input from clipboard is processed without clear indication of validation boundaries. Fix: Implement proper validation and sanitization of clipboard data. Document clipboard access permissions. Consider warning users about clipboard data access in security documentation.
  • Low · Derive Macro Complexity — druid-derive/src/data.rs, druid-derive/src/lens.rs, druid-derive/tests/ui. The druid-derive crate generates code for Data and Lens traits. Complex code generation can introduce subtle vulnerabilities if not thoroughly tested. The presence of UI tests (.stderr files) suggests known edge cases. Fix: Ensure comprehensive unit and integration tests for macro expansion. Review generated code for unsafe patterns. Add fuzzing tests for macro input validation. Document any limitations or security assumptions.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · linebender/druid — RepoPilot