GPUI Box GitHub

Components / overlay

Glass builder

A glass surface: optionally scattered and bent backdrop, optional fill, and caller-owned content.

A builder is RenderOnce. Construct and mount it in one expression.

use gpui_kit::overlay::Glass;

Reviewed in glass glass-optics glass-materials.

Construct
new(ident: impl Into<Ident>) -> Self
Options

Chain onto the value.

surface(surface: Surface) -> Self
focused(focused: bool) -> Self
elevation(elevation: Elevation) -> Self
radius(radius: Radius) -> Self
radius_px(radius: f32) -> Self
blur(blur: f32) -> Self
preset(preset: GlassPreset) -> Self
thickness(thickness: f32) -> Self
refractive_index(refractive_index: f32) -> Self
backdrop_depth(backdrop_depth: f32) -> Self
refraction(refraction: f32) -> Self
dispersion(dispersion: f32) -> Self
specular(specular: f32) -> Self
light_angle(radians: f32) -> Self
track_pointer(track_pointer: bool) -> Self
pressable(pressable: bool) -> Self
adaptive(adaptive: bool) -> Self
adaptive_appearance(adaptive: bool) -> Self
dimmed(dimmed: bool) -> Self
protect_text_contrast(protect: bool) -> Self
tint(tint: impl Into<Hsla>) -> Self
edge_mask(edge: GlassEdge, band: f32) -> Self
child(child: impl IntoElement) -> Self
Example ยท glass
fn glass(_window: &mut Window, cx: &mut App) -> AnyElement {
    let theme = cx.theme().clone();
    let label = |title: &'static str, body: &'static str| {
        div()
            .column()
            .gap(px(theme.space(Space::Xs)))
            .p(px(theme.space(Space::Md)))
            .child(div().type_scale(&theme, TypeScale::Label).child(title))
            .child(div().type_scale(&theme, TypeScale::Caption).child(body))
    };

    // A ruled checkerboard makes the material contract visible: Regular's
    // rim refracts the scattered source, bending colour and luminance bands
    // without restoring recognizable fine lines. Clear stays sharp because
    // its blur is zero. The board is neutral, and every plate is an exact
    // number of squares across and down: a board cut through the middle of a
    // square at the plate edge reads as a broken pattern rather than as the
    // ruled backdrop the optics are being measured against.
    let checker_light = theme.colors.text_faint;
    let checker_dark = theme.colors.canvas;
    let checker_rule = theme.colors.divider.opacity(0.55);
    let checkerboard =
        |width: f32, height: f32| {
            let columns = (width / TILE).ceil() as usize;
            let rows = (height / TILE).ceil() as usize;
            div()
                .absolute()
                .top(px(0.0))
                .left(px(0.0))
                .w(px(width))
                .h(px(height))
                .column()
                .overflow_hidden()
                .children((0..rows).map(|row| {
                    div()
                        .flex()
                        .flex_none()
                        .h(px(TILE))
                        .children((0..columns).map(move |column| {
                            div().flex_none().w(px(TILE)).h(px(TILE)).bg(
                                if (row + column) % 2 == 0 {
                                    checker_light
                                } else {
                                    checker_dark
                                },
                            )
                        }))
                }))
                .children((0..=(width / 12.0) as usize).map(|column| {
                    div()
                        .absolute()
                        .top(px(0.0))
                        .left(px(column as f32 * 12.0))
                        .w(px(1.0))
                        .h(px(height))
                        .bg(checker_rule)
                }))
                .children((0..=(height / 12.0) as usize).map(|row| {
                    div()
                        .absolute()
                        .top(px(row as f32 * 12.0))
                        .left(px(0.0))
                        .w(px(width))
                        .h(px(1.0))
                        .bg(checker_rule)
                }))
        };

    let plate =
        |ident: &'static str, preset: GlassPreset, title: &'static str, body: &'static str| {
            div()
                .relative()
                .h(px(PLATE_HEIGHT))
                .w(px(PLATE_WIDTH))
                .surface(&theme, Surface::Panel)
                .radius(&theme, Radius::Card)
                .overflow_hidden()
                .child(
                    if preset == GlassPreset::Clear || ident == "scene.glass.media" {
                        gpui::img(glass_media())
                            .object_fit(gpui::ObjectFit::Cover)
                            .w(px(PLATE_WIDTH))
                            .h(px(PLATE_HEIGHT))
                            .into_any_element()
                    } else {
                        checkerboard(PLATE_WIDTH, PLATE_HEIGHT).into_any_element()
                    },
                )
                .when(ident == "scene.glass.liquid", |element| {
                    element.child(div().absolute().inset_0().child(filler(
                        &theme,
                        "Document text behind Regular glass",
                        6,
                    )))
                })
                .child(
                    div()
                        .absolute()
                        .top(px(28.0))
                        .left(px(52.0))
                        .w(px(280.0))
                        .child(
                            Glass::new(ident)
                                .preset(preset)
                                .dimmed(preset == GlassPreset::Clear)
                                .adaptive(true)
                                .radius(Radius::Dialog)
                                .child(label(title, body)),
                        ),
                )
        };

    stack(&theme)
        .w(px(900.0))
        .child(caption(
            &theme,
            "Clear: dark Frosted / reduced transparency           Clear + 35% dimming / media only",
        ))
        .child(
            row(&theme)
                .child(crate::foundation::ThemeOverlay::theme(
                    theme.clone().with_reduce_transparency(true),
                    plate(
                        "scene.glass.frosted",
                        GlassPreset::Clear,
                        "Clear: reduced transparency",
                        "Dark Frosted and light content in every theme",
                    ),
                ))
                .child(plate(
                    "scene.glass.clear",
                    GlassPreset::Clear,
                    "Clear + dimmed",
                    "A sharp media fixture, never default chrome",
                )),
        )
        .child(caption(
            &theme,
            "Regular over text and media: blur, achromatic wash, lensing and hairline",
        ))
        .child(
            row(&theme)
                .child(plate(
                    "scene.glass.liquid",
                    GlassPreset::Liquid,
                    "Regular Liquid",
                    "Large reading surfaces keep the window appearance",
                ))
                .child(plate(
                    "scene.glass.media",
                    GlassPreset::Liquid,
                    "Regular on media",
                    "The same material, not the Clear variant",
                )),
        )
        .child(caption(
            &theme,
            "Compact Regular controls: appearance may flip; no opaque face",
        ))
        .child(
            div()
                .relative()
                .h(px(TILE * 2.0))
                .w(px(PLATE_WIDTH))
                .surface(&theme, Surface::Panel)
                .radius(&theme, Radius::Card)
                .overflow_hidden()
                .child(div().absolute().inset_0().bg(gpui::white()))
                .child(
                    div()
                        .absolute()
                        .right_0()
                        .top_0()
                        .w(px(PLATE_WIDTH / 2.0))
                        .h_full()
                        .bg(gpui::black()),
                )
                .child(
                    div()
                        .absolute()
                        .inset_0()
                        .flex()
                        .items_center()
                        .justify_center()
                        .gap(px(theme.space(Space::Sm)))
                        .child(
                            Glass::new("scene.glass.regular.one")
                                .preset(GlassPreset::Liquid)
                                .surface(Surface::Raised)
                                .radius(Radius::Pill)
                                .adaptive(true)
                                .child(
                                    div()
                                        .w(px(110.0))
                                        .h(px(32.0))
                                        .flex()
                                        .items_center()
                                        .justify_center()
                                        .child("Portal"),
                                ),
                        )
                        .child(
                            Glass::new("scene.glass.regular.two")
                                .preset(GlassPreset::Liquid)
                                .radius(Radius::Pill)
                                .adaptive(true)
                                .child(
                                    div()
                                        .w(px(110.0))
                                        .h(px(32.0))
                                        .rounded(px(theme.radius(Radius::Pill)))
                                        .bg(theme.colors.selected)
                                        .flex()
                                        .items_center()
                                        .justify_center()
                                        .child("Harbour"),
                                ),
                        ),
                ),
        )
        // The last two demonstrations sit side by side so the whole scene
        // stays inside the window a real display can give the gallery, which
        // is where the DirectX renderer gets looked at.
        .child(
            div()
                .flex()
                .flex_row()
                .gap(px(theme.space(Space::Md)))
                .child(
                    div()
                        .column()
                        .gap(px(theme.space(Space::Sm)))
                        .child(caption(&theme, "Fused: two panes joined into one body"))
                        .child(
                            div()
                                .relative()
                                .h(px(PLATE_HEIGHT))
                                .w(px(JOIN_WIDTH))
                                .surface(&theme, Surface::Panel)
                                .radius(&theme, Radius::Card)
                                .overflow_hidden()
                                .child(checkerboard(JOIN_WIDTH, PLATE_HEIGHT))
                                .child(
                                    div().absolute().top(px(40.0)).left(px(40.0)).child(
                                        GlassGroup::new("scene.glass.fused")
                                            .preset(GlassPreset::Liquid)
                                            .radius(Radius::Dialog)
                                            .gap(12.0)
                                            .pane(
                                                "scene.glass.fused.left",
                                                label("Left", "One lobe of the body"),
                                            )
                                            .pane(
                                                "scene.glass.fused.right",
                                                label("Right", "Joined across the gap"),
                                            ),
                                    ),
                                ),
                        ),
                )
                .child(
                    div()
                        .column()
                        .gap(px(theme.space(Space::Sm)))
                        .child(caption(&theme, "Large adaptive surfaces never flip"))
                        .child(
                            div()
                                .relative()
                                .h(px(PLATE_HEIGHT))
                                .w(px(JOIN_WIDTH))
                                .surface(&theme, Surface::Panel)
                                .radius(&theme, Radius::Card)
                                .overflow_hidden()
                                .child(
                                    div()
                                        .absolute()
                                        .top(px(0.0))
                                        .left(px(0.0))
                                        .w(px(JOIN_WIDTH / 2.0))
                                        .h(px(PLATE_HEIGHT))
                                        .bg(gpui::white()),
                                )
                                .child(
                                    div()
                                        .absolute()
                                        .top(px(0.0))
                                        .left(px(JOIN_WIDTH / 2.0))
                                        .w(px(JOIN_WIDTH / 2.0))
                                        .h(px(PLATE_HEIGHT))
                                        .bg(gpui::black()),
                                )
                                .child(
                                    div()
                                        .absolute()
                                        .top(px(28.0))
                                        .left(px(15.0))
                                        .w(px(160.0))
                                        .child(
                                            Glass::new("scene.glass.adaptive.bright")
                                                .preset(GlassPreset::Liquid)
                                                .radius(Radius::Dialog)
                                                .adaptive(true)
                                                .adaptive_appearance(true)
                                                .child(label(
                                                    "Bright",
                                                    "The reading lands next frame",
                                                )),
                                        ),
                                )
                                .child(
                                    div()
                                        .absolute()
                                        .top(px(28.0))
                                        .left(px(JOIN_WIDTH / 2.0 + 15.0))
                                        .w(px(160.0))
                                        .child(
                                            Glass::new("scene.glass.adaptive.dark")
                                                .preset(GlassPreset::Liquid)
                                                .radius(Radius::Dialog)
                                                .adaptive(true)
                                                .child(label("Dark", "The same glass, other side")),
                                        ),
                                ),
                        ),
                ),
        )
        .child(caption(
            &theme,
            "Focused: one inward report edge โ€” Regular, Clear + dimmed, Frosted, reduced",
        ))
        .child(
            row(&theme).children(
                [
                    ("regular", GlassPreset::Liquid, false, "Regular"),
                    ("clear", GlassPreset::Clear, false, "Clear + dimmed"),
                    ("frosted", GlassPreset::Frosted, false, "Frosted"),
                    ("reduced", GlassPreset::Clear, true, "Reduced"),
                ]
                .into_iter()
                .map(|(name, preset, reduced, title)| {
                    div()
                        .relative()
                        .w(px(210.0))
                        .h(px(96.0))
                        .radius(&theme, Radius::Card)
                        .overflow_hidden()
                        .child(
                            gpui::img(glass_media())
                                .size_full()
                                .object_fit(gpui::ObjectFit::Cover),
                        )
                        .child(
                            div()
                                .absolute()
                                .left(px(12.0))
                                .right(px(12.0))
                                .top(px(24.0))
                                .child(crate::foundation::ThemeOverlay::theme(
                                    theme.clone().with_reduce_transparency(reduced),
                                    Glass::new(format!("scene.glass.focused.{name}"))
                                        .preset(preset)
                                        .dimmed(preset == GlassPreset::Clear)
                                        .focused(true)
                                        .radius(Radius::Pill)
                                        .child(
                                            div()
                                                .w_full()
                                                .h(px(40.0))
                                                .flex()
                                                .items_center()
                                                .justify_center()
                                                .type_scale(&theme, TypeScale::Label)
                                                .child(title),
                                        ),
                                )),
                        )
                }),
            ),
        )
        .child(caption(
            &theme,
            "Budget fallback: opaque cards, never holes โ€” R keeps its focus report",
        ))
        .child(div().flex().gap(px(4.0)).children(('A'..='R').map(|name| {
            Glass::new(format!("scene.glass.budget.{name}"))
                .focused(name == 'R')
                .child(
                    div()
                        .w(px(38.0))
                        .h(px(30.0))
                        .flex()
                        .items_center()
                        .justify_center()
                        .child(name.to_string()),
                )
        })))
        .child(caption(
            &theme,
            "Nine lobes exceed the fused budget: every pane retains an opaque face",
        ))
        .child(
            ('A'..='I').fold(GlassGroup::new("scene.glass.lobe-budget"), |group, name| {
                group.pane(
                    format!("scene.glass.lobe-budget.{name}"),
                    div()
                        .w(px(58.0))
                        .h(px(30.0))
                        .flex()
                        .items_center()
                        .justify_center()
                        .child(name.to_string()),
                )
            }),
        )
        .into_any_element()
}

Source: crates/gpui-kit/src/overlay/glass.rs