Documentation
¶
Overview ¶
Package depth renders Material-style cast shadows under rectangular regions by composing linear gradients.
An explicit effect, never a default ¶
A shadow is opt-in vibrancy, not something a component gets for being raised. Per ADR-005, a raised surface on desktop reads as raised by tint first and shadow second: it names its rung on tokens.ElevationScale and paints the neutral-ramp colour that (tokens.ColorTokens).SurfaceAt resolves — one fill, no shadow. A shadow is right only for what floats and can leave: transient, dismissible surfaces above the plane — a toast, a popover, a menu, a drag preview. What is raised in place — a card, a header, static hierarchy — reads as raised by its surface step alone, and no component should default into calling this package for it.
The cost difference backs the rule. One Shadow call issues eight paint.LinearGradientOp fills — four edge bands and four corner tiles — plus one interior fill: nine paint operations per shadow, every frame it is drawn. A surface step is a single paint.FillShape.
Caller audit (E2.2) ¶
The organization's three callers, judged against that criterion:
- cadence/toast keeps its shadow: a toast floats over the content plane and leaves on its own, and on dark themes the shadow, not the fill, is what separates it.
- workbench/mindchat's undo bar keeps its shadow: a transient bar floating over the chat surfaces, a toast by another name. (App code is not governed by this verdict; recorded as guidance.)
- cadence/card's Elevated variant loses its shadow: a card is raised in place, so it becomes a level-2 surface fill. E2.3 executes the migration.
Geometry ¶
A shadow is a soft black fringe around a "shadow rectangle" — the caller's bounds shifted downward by half the elevation extent — to approximate light from above. The geometry mirrors github.com/vibrantgio/pulse/glow.Halo but with two differences:
- The shadow rectangle's interior is filled at the peak alpha too, so the strip extending below bounds stays visible once the caller paints their foreground on top.
- Nothing about the colour is a parameter. It is a fixed key-shadow black; the peak alpha scales only with the caller's opacity, and neither varies with the elevation level — only the geometry does.
Extent (the gradient's falloff distance) and offset (the downward shift of the shadow rectangle) both follow the level: extent is the level's dp value from tokens.Elevation converted to pixels through gtx.Metric, and offset is half of that. tokens.Level0 — and any level whose dp rounds to zero pixels at the current density — paints nothing at all.
Rounding and opacity (FX.3) ¶
The two geometry traps E2.2 recorded are parameters now. The interior fill is a clip.RRect at the caller's radius, so a caller passing the same radius it rounds its foreground to no longer gets square dark wedges showing through the rounded corners; the corner tiles of the penumbra grow inward to cover the notch between the rounded interior and the old square corner, keeping the alpha ramp seam-free. And opacity scales the whole ramp, so a shadow that fades with its surface — cadence/toast's — passes its fade alpha straight through instead of wrapping the call in a paint.PushOpacity layer. Radius 0 and opacity 1 reproduce the old square, full-strength shadow exactly.
One thing a caller trips on ¶
The black is not a token role, so it does not follow the theme. The same call separates a surface strongly on a light background and barely at all on a dark one; a dark theme that wants visible elevation needs something other than this package.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Shadow ¶
func Shadow(gtx layout.Context, bounds image.Rectangle, level tokens.ElevationLevel, radius int, opacity float32)
Shadow paints a Material-style cast shadow under bounds onto gtx.Ops at the given elevation level. The shadow is biased downward to approximate light from above.
radius rounds the shadow rectangle's corners, in pixels. Callers pass the radius they round their foreground to, so the interior fill cannot show through the rounding as square wedges; 0 keeps the square geometry. opacity scales the shadow's alpha ramp and is clamped to [0, 1]; a shadow that fades with its surface passes the surface's fade alpha here.
At tokens.Level0 (and any level whose dp value rounds to zero pixels at the current metric), and at opacity 0, the function is a no-op.
Types ¶
This section is empty.