gpui-ai

Effects · Decoration

Halftone

A grid of dots on a travelling wave, on the library's motion channel. It stops when the panel scrolls out of view.

Halftone — gpui-ai

Starts when it scrolls into view

Pop out

NORD FROST · DARK · RADIUS 6/10 · BASE 16PX · SHADOW

The decorations story, opened on Halftone. The switcher above the card is the story's own — every state it offers has a page here.

Code

Cut from the gallery’s own decorations, so it is the code that drew the frame above rather than a description of it.

crates/gallery/src/decorations.rsOpen in the galleryImplementation
fn halftone(cx: &App) -> impl IntoElement {
    const COLUMNS: usize = 22;
    const ROWS: usize = 9;
    let ink = cx.theme().primary.opacity(0.55);
    let radius = f32::from(decoration::frame_radius(cx));
    decoration::animated("halftone", Duration::from_secs(6), move |delta| {
        // One wave crossing the grid, so a dot's size depends on where it is
        // as well as when it is — a field rather than a pulse.
        let phase = delta * std::f32::consts::TAU;
        div()
            .size_full()
            .children((0..ROWS * COLUMNS).filter_map(move |cell| {
                let (row, column) = (cell / COLUMNS, cell % COLUMNS);
                let across = (column as f32 / COLUMNS as f32) * std::f32::consts::TAU;
                let wave = (phase + across + row as f32 * 0.6).sin() * 0.5 + 0.5;
                let size = 3.0 + wave * 13.0;
                let x = (column as f32 + 0.5) * CARD.width / COLUMNS as f32;
                let y = (row as f32 + 0.5) * CARD.height / ROWS as f32;
                Some(dot(x, y, size, radius)?.bg(ink))
            }))
    })
}

Applying it

Every framed component takes a Decoration, and the layer decides for itself whether it belongs to the shape — either by carrying the frame’s radius, or by not reaching a corner. The two rules are the whole contract.

crates/gallery/src/decorations.rs
let card = ApprovalCard::new("decorated-gate", "Publish the launch plan?")
    .description(
        "The card is unchanged. Everything behind and in front of it \
         is the application's.",
    )
    .decoration(kind.build(cx))