bezel README

The project's README from github.com/crabtalk/bezel. As one markdown file: README.md.

bezel

crates.io license gpui

A gpui component library, SwiftUI-lean: style flows through the environment, never through parameters, and its numbers are measured rather than chosen — the type ladder is NSFont.preferredFont(forTextStyle:), the gap between siblings is NSStackView().spacing. CONTRIBUTING.md has the laws.

https://github.com/user-attachments/assets/34861f29-004f-47f0-89e6-42cc8772749f

use bezel::ui::widgets::{ButtonStyle, Buttons};
theme.button("Save", ButtonStyle::Prominent, None)

Install

[dependencies]
bezel = "0.1"

An app also names the two crates the facade cannot cover — gpui because actions! expands to literal gpui:: paths, and gpui_platform because the facade re-exports gpui but not the platform. Both are our fork of gpui, published under bezel-gpui*; the package key keeps the gpui:: paths the macros and gpui's own docs expect:

gpui = { package = "bezel-gpui", version = "0.3" }
gpui_platform = { package = "bezel-gpui-platform", version = "0.3", features = ["font-kit"] }

Theme

Most apps want the shipped palette in their own hues. That is a Brand — one hue for the greys, one for the accent, one base radius:

use bezel::theme::{self, Brand, Tint};

// before appearance::init
theme::set_brand(
    Brand {
        tint: Tint::new(257.417, 0.046),
        accent: Tint::new(276.935, 0.182),
        radius: 8.0,
    },
    cx,
);

Lightness is not a knob, so a branded palette keeps the contrast ratios the shipped one was verified at. The gallery's Theme page is this struct with sliders on it, and prints the call back.

For colors a hue rotation cannot reach, register a palette builder instead — it runs first, and a brand rotates whatever it returns:

use bezel::theme::{Theme, set_palette};

theme::set_palette(|appearance| {
    let mut theme = Theme::for_appearance(appearance);
    theme.danger = my_red(appearance);
    theme
}, cx);

Build an app

apps/hello is the smallest consumer — one window, a button, a toggle. Every gpui type path goes through bezel::gpui, so a second gpui cannot creep into the graph. The bootstrap, which is the part no snippet can skip:

use bezel::gpui::{App, AppContext as _, Bounds, WindowBounds, WindowOptions, px, size};
use bezel::theme::{self, Theme};
use bezel::ui;

fn main() {
    gpui_platform::application()
        .run(|cx: &mut App| {
            if let Err(err) = ui::register_fonts(cx) {
                eprintln!("FONT REGISTRATION FAILED: {err:?}");
            }
            theme::appearance::init(theme::appearance::AppearanceMode::System, cx);
            let bounds = Bounds::centered(None, size(px(520.0), px(360.0)), cx);
            cx.open_window(
                WindowOptions {
                    window_bounds: Some(WindowBounds::Windowed(bounds)),
                    ..Default::default()
                },
                |window, cx| {
                    theme::appearance::observe_window(window, cx).detach();
                    cx.new(Hello::new)
                },
            )
            .unwrap();
            cx.activate(true);
        });
}

Hello is a struct implementing Render; its render reads the theme with Theme::of(cx) and builds elements through the widgets traits. Run cargo run -p hello and read apps/hello/src/main.rs for the rest.

Agents

Every doc page is served as markdown — append .md to any docs URL, or take the whole corpus from llms.txt and llms-full.txt.

skills/ holds two agent skills, plain SKILL.md files any agent that reads the format can load. skills/bezel teaches an agent to use the library — the bootstrap, the laws, and the traps that only bite at runtime. skills/bezel-contributing is for working on it.

Provenance

What From License
Initial components comet MIT
Thinking orbs gpui-thinking-orbs MIT
Blob avatars blobatar MIT
Syntax highlighting tree-sitter core and grammars MIT
TypeScript/TSX queries nvim-treesitter Apache-2.0
Icons Lucide, via icondata_lu ISC
Fonts Geist and Geist Mono © Vercel Inc. SIL OFL 1.1

bezel (crabtalk/bezel)

Searching Database…

182 ·GitHub
这是什么?Bezel 是 GPUI(Rust UI 框架)的组件库——一套精简程度堪比 SwiftUI 的原生桌面组件,样式通过环境传递,而从不通过组件参数。
“精简程度堪比 SwiftUI”在实践中是什么意思?样式放在环境里,而不是组件参数里,而且数值都是实测得来的,不是随意选的:字体层级来自 NSFont.preferredFont(forTextStyle:),兄弟元素间距来自 NSStackView().spacing。
怎么让第一个应用跑起来?运行 cargo run -p hello——apps/hello 是最小的消费者,只有一个窗口,带一个按钮和一个开关。它的 render 通过 Theme::of(cx) 读取主题,并通过 widgets 这些 trait 来构建元素。
除了 bezel 本身,我还需要引入其他 crate 吗?需要——除了这个门面 crate,你的应用还要声明 gpui 和 gpuiplatform,它们是 bezel 自己 fork 的 gpui,以 bezel-gpui 的名字发布,这样宏和文档里字面上的 gpui:: 路径才能继续使用。
我想给自己的应用换主题,能换到什么程度?一个 Brand 会为灰色系设定一个色调、一个强调色和一个基础圆角。明度不是可调参数,所以品牌化配色仍能保持发布版本经过验证的对比度。
这是做桌面应用、移动端还是网页用的?仅限桌面:bezel 面向 GPUI 这个原生 Rust UI 框架,仓库列出的支持平台是 macOS、Linux 和 Windows。
有没有可视化的方式来玩主题?有——仓库自带一个画廊应用,它的 Theme 页面就是加上了滑块的 Brand 结构体;还会打印出可以直接粘贴到你应用里的回调代码。对于色相旋转调不出来的颜色,可以改为注册一个调色板构建器。
AI 编程助手能配合 bezel 使用吗?能——每个文档页面都有 markdown 版本:在任何文档 URL 后面加 .md,或者从 llms.txt 和 llms-full.txt 获取全部文档。skills/ 里还带两个 SKILL.md 技能:beel 用于使用这个库,bezel-contributing 用于参与开发。
这些组件和素材来自哪里?有一张来源表注明出处:最初的组件来自 comet,此外还有思考动画球、blob 头像、tree-sitter 语法高亮、Lucide 图标和 Geist 字体——大部分是 MIT 许可,少数例外采用 Apache-2.0、ISC 和 SIL OFL。
Creator
crabtalk
Size
4.8 MB
Stars
182
Age
2mo
Commits · 90 Days