Theme
Customize the design system

Every control starts at the preset. Change one and every preview on the site follows, on this page and the next, until you reset it.

Contrast

Text against what it sits on. Below 4.5:1 fails WCAG AA for body text — the check a reviewer runs on any surface that takes a tone.

Waiting for the first preview to report its palette.

Corners

Sets all three radii at once. The individual values are under Geometry.

Brand 5

The accent seam an app actually brands itself through. Change these and you have made the decision a real `DesignTokens.graphite(...)` call makes.

Geometry 15

Square or rounded, and how heavy every line is. The radius row above the controls sets all three corners at once, because "what does square feel like" is one decision rather than three numbers.

Surfaces 17

Everything the app is painted ON — the ground behind the content (the frame paints it too), the cards over it, the well inset in a card, and the washes that show state.

Bands 10

The rail's head and the view bar beside it (one band across the top at 960 and wider), a pushed screen's bar, the compact bar and the compact nav bar — the band's fill, its rule, its hover and active faces, the resting field box on it, and the ink and accent control that sit on it. The rail's tree and its footer stay on the ground.

Text and controls 11

The ink ramp, the control outlines and the field's focus halo. Every pair the panel can break is watched by a contrast badge above.

Status 7

The three voices that mean something — danger, caution and ok — each as a foreground and a surface wash, danger with a border as well.

Data 5

The default pin head, its glyph and its halo, and the group bands. A pin's category color comes from the palette, named in the theme seed.

Map 11

The basemap's roles — land, water, parks, roads and their casings, buildings, labels — and the pending pin's gray. A raster basemap keeps its own imagery; these paint the map's plate and any kit-drawn map.

Scrollbars 6

Every scroller's bar: the thumb at rest and while hovered or dragged, the strip it rides, and the desk bar's thickness, side gap and corners. The desk half shows only while a fine pointer is attached; at touch the platform's own overlay keeps its size.

Advanced 6

Real controls that are not decisions — motion durations, the focus ring offset, the touch floor. Opens collapsed on purpose.

Take it with you

The Dart that reproduces what you are looking at. It is a real constructor call, because the configurator edits a real preset — what you copy is what an app can paste.

Components

Identity and media

How a record shows who and what it is — the avatar whose hue is derived from the name, who else is here (the presence stack and the badge on a focused item), the id chip, and the media header including its real no-image fallback.

Spec of record: design-system/components/data/Avatar.d.ts

0
Knobs

Live

Real widgets, built from the real kit. Turn a knob and it rebuilds; the theme bar above applies the design system's own tokens — including anything you changed under Customize — and the device selector uses the same sizes the golden baselines gate on, so what you see here is what CI holds the widget to.

Press Focus on any preview to take it to the full window — at a desktop width that renders most devices at 1:1, which is when the widget's own controls become clickable. The bar always states the device and the scale, so a shrunk preview says it is shrunk. Esc leaves.

family_identity
Knobs
Theme
Dart for these values
family_identity()

What it is made of

The widgets this screen assembles, with their full API below. They used to live on a second entry of their own; one thing you choose gets one page.

AppAvatar widget

The design-system Avatar — the identity block. A square at the chip and badge radius (DesignTokens.rXs) carrying a person's initials (or their image when one exists), sitting in the leading slot of thread cards, feed posts, tagged chips, and account rows.

Full dartdoc

The design-system Avatar — the identity block. A square at the chip and badge radius (DesignTokens.rXs) carrying a person's initials (or their image when one exists), sitting in the leading slot of thread cards, feed posts, tagged chips, and account rows. Identity, never status. Sanctioned size steps with their initial sizes: 32→11 · 28→10 · 22→9 · 20→9 · 16→8 (feed/compose · card/composer · reply · level-3 · tagged chip). Non-interactive; name is the semantic label. ```dart const AppAvatar(name: 'Adeyemi Okafor', size: 32) const AppAvatar(name: 'You', hue: AppAvatarHue.mono) AppAvatar(name: me.name, image: NetworkImage(me.avatarUrl)) ```

AppAvatardefault constructor

Knob Type Default What it does
hue AppAvatarHue
identity · mono
AppAvatarHue.identity Identity hue (default) or the monochrome block.
image ImageProvider? null Avatar image; cover-fit, initials fallback on failed load.
name * String — Full display name — the initials source, the hash input, and the semantic label.
size double 28 Edge length. Sanctioned steps: 16 · 20 · 22 · 28 · 32.

AppPresenceStack widget

The faces of the OTHER people in a scope (`Presence.d.ts` PresenceStack): one AppAvatar each, a 2px gap and no overlap, at most max slots with the last one the `+N` overflow block. The whole stack is ONE button opening an anchored list that names every member and whether they are viewing or editing.

Full dartdoc

The faces of the OTHER people in a scope (`Presence.d.ts` PresenceStack): one AppAvatar each, a 2px gap and no overlap, at most max slots with the last one the `+N` overflow block. The whole stack is ONE button opening an anchored list that names every member and whether they are viewing or editing. Empty renders nothing. Pass it to `AppHeaderBar.presence` — the one place a floorplan shows presence: ```dart AppHeaderBar( title: 'Work order', presence: AppPresenceStack( members: ref.watch(presenceProvider(scope)).members, ), syncStatus: sync, ) ```

AppPresenceStackdefault constructor

Knob Type Default What it does
max int 3 Slots before the overflow; the `+N` block takes the last one.
members * List<PresenceMember> — The other people here, in display order.
size double 24 Face size: sanctioned 24 · 28.

AppPresenceBadge widget

"Sam Lee is editing" on an item another person has in focus (`Presence.d.ts` PresenceBadge): a 16 face and the sentence on the well plate. A list row, a form field and a markup annotation all use this one badge. label replaces the sentence; the face is unchanged.

AppPresenceBadgedefault constructor

Knob Type Default What it does
label String? null A host's own wording, in place of the sentence.
member * PresenceMember — The person holding the focus.

AppIdChip widget

The design-system IdChip — how a record says its name. Renders id (e.g. `WO-2041`, `SR-1042`) in DesignTokens.dataS (the small mono/data face) on a faint DesignTokens.accentTint square, radius DesignTokens.rS.

Full dartdoc

The design-system IdChip — how a record says its name. Renders id (e.g. `WO-2041`, `SR-1042`) in DesignTokens.dataS (the small mono/data face) on a faint DesignTokens.accentTint square, radius DesignTokens.rS. This is the system's **ID grammar**: one per row, leading position — never a pill, never used for statuses (a status is a word per the constitution's "encode once" rule). Two modes: * **Static** (default, onTap null) — a plain labeled chip, not interactive. No Semantics button role, no focus/hover/press paint. * **Tappable** (onTap set) — some ID chips navigate to the record they name. Becomes a real focusable/tappable target with the state contract: enabled · hover (DesignTokens.ink4 wash, pointer enhancement only) · focus-visible (1px solid accent, zero offset) · pressed (1px translateY). The tap target is expanded to at least DesignTokens.touch even though the visual chip is compact. title feeds a Tooltip and, for the tappable form, the accessible name; for the static form it is exposed as a plain Semantics label. ```dart const AppIdChip(id: 'WO-2041') AppIdChip(id: 'SR-1042', onTap: () => openRecord('SR-1042')) ```

AppIdChipdefault constructor

Knob Type Default What it does
id * String — The record ID text, e.g. `WO-2041`. Rendered in DesignTokens.dataS, one line, never wrapped.
onTap VoidCallback? null Fires when the chip is tapped. Null renders the static (non-tappable) form — no Semantics button role, no hover/focus/press paint.
title String? null Tooltip text and accessibility hint. Falls back to id for the Semantics label when null.

AppMediaHeader widget

The design-system media header — a hero image band with a bottom scrim and slotted overlay content. Any surface, zero domain knowledge: image is a stored image reference fed verbatim to AppImage's resolution ladder (`staged://` / `asset:` / `http(s)://` / origin-relative / blank), and overlay is a…

Full dartdoc

The design-system media header — a hero image band with a bottom scrim and slotted overlay content. Any surface, zero domain knowledge: image is a stored image reference fed verbatim to AppImage's resolution ladder (`staged://` / `asset:` / `http(s)://` / origin-relative / blank), and overlay is a caller-built widget (title / status / actions) laid over the scrim. A blank/absent image renders the hairline-framed glyph placeholder — the band keeps its height so a layout does not jump between records with and without a photo. Anatomy (bottom to top): the image layer (over an DesignTokens.ink4 void, BoxFit.cover by default), a bottom-anchored scrim gradient (DesignTokens.scrim → transparent, enabled by default so overlay text stays legible over arbitrary photo pixels), the overlay slot inset from the band's start + bottom edges, and a bottom structural hairline framing the band off the content below. **Scrim.** The gradient rises from DesignTokens.scrim at the bottom to transparent at mid-band. Set scrim false to drop it (e.g. when the overlay carries its own background, or there is no overlay). With no overlay the scrim still paints when enabled — callers usually pass `scrim: false` there. **Placeholder.** When image is blank the band renders a centered DesignTokens.ink40 image glyph over an DesignTokens.paperW wash — the same "no image, identity only" grammar as the cell/gallery thumbs, at band scale. The overlay still renders over the placeholder. State/semantics: purely presentational — it renders and never navigates. When onTap is set the whole band becomes a button (e.g. open a full-screen viewer); the accessible name comes from semanticLabel. Reduced motion (reducedMotionOf — the framework flag OR the platform's own Reduce Motion) drops the Hero flight, and so does the desk posture, where navigation cuts. ```dart AppMediaHeader( image: observation.photoRef, // '' → framed placeholder heroTag: 'obs-image-${observation.id}', overlay: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(observation.title, style: onScrimTitleStyle), Text(status, style: onScrimSubStyle), ], ), onTap: openViewer, semanticLabel: 'Observation photo', ) ```

AppMediaHeaderdefault constructor

Knob Type Default What it does
fit BoxFit BoxFit.cover How the image inscribes the band (default BoxFit.cover; pass BoxFit.contain to letterbox the full image over the DesignTokens.ink4 void).
height double _defaultHeight The band height in logical pixels. Fixed so a layout does not jump between records with and without a photo.
heroTag Object? null Optional Hero tag for the image layer. When set (and neither reduced motion nor the desk posture holds — at the desk navigation cuts, with "no flight at all") the photo flies between this band and the surface it opens — and, sharing one tag per record, between a list/map preview and the detail…
image String '' The stored image reference, fed verbatim to AppImage's resolution ladder. Blank (the default) renders the framed glyph placeholder.
onTap VoidCallback? null Tap callback — when set the whole band becomes a button (e.g. open a full-screen viewer). Null renders a non-interactive band.
overlay Widget? null Overlay content laid over the scrim, inset from the band's start + bottom edges (a title, a status word, an actions row). Null renders no overlay.
scrim bool true Whether the bottom scrim gradient paints (DesignTokens.scrim → transparent). Default true — keeps overlay text legible over arbitrary photo pixels. Set false when there is no overlay or the overlay carries its own background.
semanticLabel String? null The accessible name for the band when onTap is set. Null falls back to a generic label.

PhotoViewer widget

The full-screen zoomable photo viewer body — a plain paper surface under an AppHeaderBar close control, the image inscribed `contain` inside an InteractiveViewer (pinch/drag zoom up to 4x). Normally reached via openPhotoViewer; public so a host with its own route table can mount it there instead.…

Full dartdoc

The full-screen zoomable photo viewer body — a plain paper surface under an AppHeaderBar close control, the image inscribed `contain` inside an InteractiveViewer (pinch/drag zoom up to 4x). Normally reached via openPhotoViewer; public so a host with its own route table can mount it there instead. **No sync control here, deliberately.** The "every view carries it" convention names views; this is a lightbox over one image — a modal dismissed with an ✕, in the same family as a dialog or a sheet, none of which take the control either. The surface underneath it has one.

PhotoViewerdefault constructor

Knob Type Default What it does
imageRef * String — The image's storage reference — any AppImage ladder shape.
title String? null The header title; null renders the default.

Where it lives

Class File
AppAvatar packages/app_widgets/lib/src/kit/data/avatar.dart
AppPresenceStack packages/app_widgets/lib/src/kit/data/presence.dart
AppPresenceBadge packages/app_widgets/lib/src/kit/data/presence.dart
AppIdChip packages/app_widgets/lib/src/kit/data/id_chip.dart
AppMediaHeader packages/app_widgets/lib/src/kit/data/media_header.dart
PhotoViewer packages/app_widgets/lib/src/patterns/photo_viewer.dart