Effects · Decoration
Border beam
Nine patches of colour sitting still around the frame, and a window of brightness sweeping over them. The colours never travel - that is the whole difference between light passing through a frame and a coloured head chasing its own tail.
Starts when it scrolls into view
NORD FROST · DARK · RADIUS 6/10 · BASE 16PX · SHADOW
Code
Cut from the gallery’s own decorations, so it is the code that drew the frame above rather than a description of it.
fn beam_field(phase: f32, radius: f32, dark: bool) -> impl IntoElement {
// `sizeThemePresets.md`, which is the size a card is.
let (stroke, inner, bloom) = if dark {
(0.26_f32, 0.42_f32, 0.24_f32)
} else {
(0.12, 0.26, 0.34)
};
// (inside, size). The three layers are three sizes of the same patch,
// kept close to the spec's own: a tight one that reads as the line, one at
// full size for the glow, and a slightly wider soft one. Scaling the same
// blob by three did not work — at two and a half times it is wider than
// the card and washes the middle instead of hugging the edge.
let layers = [(true, 0.5, stroke), (true, 1.4, inner), (false, 1.9, bloom)];
div()
.absolute()
.inset_0()
.children(layers.into_iter().flat_map(move |(inside, grow, weight)| {
(0..FIELD.len()).map(move |index| {
let patch = &FIELD[index];
// Where this patch sits around the frame decides when the
// sweep reaches it. The colours stay; the light travels.
let angle = (patch.y - 0.5).atan2(patch.x - 0.5);
let around = angle / std::f32::consts::TAU + 0.25;
let lit = sweep(around - phase);
div()
.absolute()
.inset_0()
.opacity((lit * weight).clamp(0.0, 1.0))
.child(
img(patch_image(index, inside, radius, grow))
.absolute()
.inset_0(),
)
})
}))
}
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))