Components
Sky state background
Each of the six sky states has an illustrated sky drawn at half opacity under a blue wash.
Preview

Milky Way visible

Starry skies

Planets visible

Few stars

Cloudy

Too much light
Variants
Pick a variant with the controls. The preview and both code blocks follow.
State

Starry skies
Variant.tsx
<AppSkyState state="starrySkies" />Implementation
The React tab is this site's own component, the same source that draws the preview, styled by the CSS below it. The Flutter tab is the Dart a screen builds it with, from the app's tokens.
Usage
<AppSkyState state="starrySkies" note="Clear and dark" />app-widgets.tsx · AppSkyState
/** SkyStateBackground: the illustrated sky at half opacity under the blue wash, with its state name. */export function AppSkyState({ state, note }: { state: SkyStateKey; note?: string }) { const { image, label } = SKY_STATE_ASSETS[state]; return ( <div className="app-ui app-state"> {/* eslint-disable-next-line @next/next/no-img-element */} <img src={`/app/${image}.jpg`} alt="" /> <div> <div className="app-heading">{label}</div> {note && <div className="app-label-sm">{note}</div>} </div> </div> );}app-ui.css
.app-state { position: relative; overflow: hidden; flex: 1 1 var(--spacing-f144); min-height: var(--spacing-f144); border-radius: var(--radius-f21); background: var(--c-ink); border: var(--spacing-f1) solid var(--hair-strong); box-shadow: var(--highlight);}.app-state img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: var(--mag-1); }.app-state::after { content: ""; position: absolute; inset: 0; background: linear-gradient(to bottom, color-mix(in srgb, var(--c-accent) var(--mag-4), transparent), transparent); pointer-events: none; }.app-state > div { position: absolute; left: var(--spacing-f13); right: var(--spacing-f13); bottom: var(--spacing-f13); z-index: 1; }Usage
SkyStateBackground(skyState: SkyState.starrySkies)astr_glass.dart · AstrGlassCard
/// The glass surface for cards: a sheen over the surface and a hairline edge./// Cards do not glow; glow belongs to buttons and tiles. Mini cards are/// [AstrSpace.f144] wide and 144 + 21 tall.class AstrGlassCard extends StatelessWidget { const AstrGlassCard({ super.key, required this.child, this.width, this.height, }); final Widget child; final double? width; final double? height; @override Widget build(BuildContext context) { final Color text = AstrColors.spaceGrey[50]!; final BorderRadius radius = BorderRadius.circular(AstrRadius.f21); return RepaintBoundary( child: ClipRRect( borderRadius: radius, child: BackdropFilter( filter: ImageFilter.blur(sigmaX: AstrSpace.f13, sigmaY: AstrSpace.f13), child: Container( width: width, height: height, padding: const EdgeInsets.all(AstrSpace.f13), decoration: BoxDecoration( borderRadius: radius, border: Border.all(color: text.withValues(alpha: Mag.m5)), color: _ink.withValues(alpha: Mag.m1), gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: <Color>[ text.withValues(alpha: Mag.m5), text.withValues(alpha: Mag.m8), ], ), ), child: child, ), ), ), ); }}sky_state_background.dart · SkyStateBackground
class SkyStateBackground extends StatelessWidget { const SkyStateBackground({ super.key, required this.skyState, }); final SkyState skyState; @override Widget build(BuildContext context) { return Stack( fit: StackFit.expand, children: <Widget>[ const ColoredBox(color: AppColors.surface), Image.asset( SkyStateAssets.pathFor(skyState), fit: BoxFit.cover, opacity: const AlwaysStoppedAnimation<double>(0.5), ), const DecoratedBox( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: <Color>[ Color(0x33448AFF), Colors.transparent, ], ), ), ), ], ); }}sky_state_background.dart · SkyStateAssets
class SkyStateAssets { const SkyStateAssets._(); static String pathFor(SkyState state) { return switch (state) { SkyState.milkyWayVisible => 'assets/img/milky_way.jpg', SkyState.starrySkies => 'assets/img/starry_sky.jpg', SkyState.planetsVisible => 'assets/img/planets.jpg', SkyState.fewStars => 'assets/img/few_stars.jpg', SkyState.cloudy => 'assets/img/cloudy.jpg', SkyState.tooMuchLight => 'assets/img/excessive_light_pollution.jpg', }; }}API reference
| React prop | Flutter parameter | Type | Default | Meaning |
|---|---|---|---|---|
| state | skyState | SkyStateKey / SkyState | required | One of six. |
| note | none | string | none | Optional caption on the web tile. |
Design tokens
Every value on this component is a system token. The last column is what the app widget uses today, so the gap to close is visible.
| Role | CSS token | Dart token | App widget today |
|---|---|---|---|
| Min height | --spacing-f144 | AstrSpace.f144 | full screen background |
| Radius | --radius-f21 | AstrRadius.f21 | none |
| Image opacity | --mag-1 | Mag.m1 | 0.5 |
| Wash | deep-space-200 at --mag-4, top to clear | Mag.m4 | Color(0x33448AFF) |
| Label | --text-s0 | AstrType.s0 | none |