design_system

The one place where the apps and the console get their look: the generated design tokens, the theme built from them, the resolver from the personal settings to the theme inputs, the bundled fonts, the semantic icons, the core components and the shared golden test setup.

Status: tokens, theme, fonts and golden setup (M4-04), icons (M4-05), core components (M4-07). Kind: Flutter package, a member of the Dart workspace at the repository root (resolution: workspace, publish_to: none).

What the package provides

Symbol Library Content
DsColors, DsAccent, DsElevation, DsDensity, DsMotion design_system.dart generated ThemeExtension classes with one instance per context
DsPalette, DsSpace, DsRadius, DsBorderWidth, DsLayout, DsSize, DsIconSize, DsFonts, DsType, DsIcons design_system.dart generated constants
DsContext, DsThemeMode, DsDensityMode, DsMotionMode design_system.dart the four theme inputs as a value type
resolveDsContext, dsDefaultAccent design_system.dart personal settings and system values to a DsContext (pure)
buildDsTheme, dsTextStyle, DsNoTransitionsBuilder design_system.dart ThemeData of a DsContext; a type role ready for rendering
context.dsColors, dsAccent, dsDensity, dsMotion, dsElevation design_system.dart accessors on BuildContext; a StateError naming the extension when the theme was not built with buildDsTheme
DsThemeScope design_system.dart applies a DsContext with AnimatedTheme (motion.duration.fade, zero under reduced motion)
DsIcon, DsIconSizeRole, DsIconPlaceholder design_system.dart a semantic icon of DsIcons at icon.size.*; see "Icons"
DsIconAssets, dsSemanticIcons, dsIconPackage design_system.dart generated asset lookup of the icons and the list of every semantic icon
dsPumpIcons testing.dart pumpBeforeTest of a golden with icons: pumps until every icon asset is loaded
dsGoldenMatrix testing.dart one alchemist GoldenTestGroup per theme, density, text scale and locale; import it from tests only

Widgets read colors, type, spacing and motion only from these classes (ADR 0030); no literal size, color, duration or curve in widget code except 0. Type roles only, never font.size.*: take the text styles from Theme.of(context).textTheme or wrap a role with dsTextStyle(DsType.<role>), so the bundled font also resolves inside an app (see "Fonts").

Components

The core components of docs/design/components.md (M4-07). Each takes a small immutable view model of lib/src/components/view_models.dart (enums carry the codes of docs/spec/03 and an unknown member; docs/DECISIONS.md D-M4-07-1), reads every text from package:l10n, performs no I/O and reports actions through plain callbacks. Values of configuration keys are parameters; the apps pass them from the app configuration (M4-08), this package holds no number of them.

Widget View model Configuration parameters components.md
DsMessage DsMessageData, DsMessageAction collapseLines (ui.message_collapse_lines); isContinuation computed by the caller from ui.message_group_window 1
DsMarkdown the Markdown source, DsAttachmentResolver none 1
DsLiveBox, .collapsed, .mobile DsRunData, DsStepData visibleSteps (ui.livebox_visible_steps), announceMinInterval (a11y.live_announce_min_interval) 2
LiveAnnouncer run state and question ID minInterval (a11y.live_announce_min_interval) 2.4
DsToolChip DsStepData none 3
DsStatusLine the text none 4
DsTriggerStateIcon DsTriggerState and reason code none 5
DsThreadRow DsThreadRowData, DsTagData none 6
DsSpaceRow, DsChannelRow DsSpaceRowData, DsChannelRowData none 7
DsMessageComponents, DsButton DsComponentData, DsComponentItem, DsComponentHeader none 8
DsComposer DsComposerCommand, DsCommandOption maxLines (ui.composer_max_lines), enterSends (composer.enter_sends) 9
DsSuggestionList DsSuggestion none 9
DsBillingBadge, DsCostText DsBillingMode, DsCost none 10
DsBanner DsTone and text none 2.1, 6.6 of 01
DsTappable, DsBadge, dsIsolate shared building blocks none "Common rules"

Security rules held here: Markdown renders no HTML, loads no image and activates only https, http, mailto and internal links (SEC-OUT-1, SEC-OUT-2; D-M4-07-2); foreign names are wrapped in U+2068 and U+2069 for display, never in semantics labels (SEC-IN-4); origin badges for agent, app, import and system (SEC-OUT-3); the card header comes only from DsComponentHeader (SEC-OUT-4; D-M4-07-3). Tests: test/components/ (one file per component plus guidelines_test.dart for contrast, tap targets and labels), goldens in test/goldens/components/ built from the sheets in sheets.dart.

Resolver

resolveDsContext (docs/spec/01-product.md 8 and 11; docs/DECISIONS.md D-M4-04-2):

Input Value Result
appearance.theme light / dark that theme
system, absent, unknown platformBrightness
appearance.density any, on a touch platform touch
compact (desktop) compact
comfortable, absent, unknown (desktop) comfortable
appearance.reduce_motion on reduced
off full
system, absent, unknown reduced when the platform asks for reduced motion, else full
accent (branding.accent_color) a key of DsAccent that key
absent, unknown spruce

Color scheme mapping

buildDsTheme maps the tokens into the Material ColorScheme (docs/DECISIONS.md D-M4-04-3); accent roles come from DsAccent of the context's accent and brightness, all others from DsColors of the theme.

ColorScheme Token
primary color.accent.bg (DsAccent.accentBg)
onPrimary color.text.on-accent
primaryContainer color.accent.subtle (DsAccent.accentSubtle)
onPrimaryContainer, secondary color.accent.fg (DsAccent.accentFg)
onSecondary color.surface.canvas
secondaryContainer color.surface.selected
onSecondaryContainer, onSurface color.text.primary
tertiary / onTertiary color.info.bg / color.info.on-bg
error / onError color.danger.bg / color.danger.on-bg
errorContainer / onErrorContainer color.danger.subtle / color.danger.fg
surface, surfaceTint color.surface.canvas
onSurfaceVariant color.text.secondary
surfaceContainerLowest color.surface.sunken
surfaceContainerLow color.surface.list
surfaceContainer, surfaceContainerHigh color.surface.raised
surfaceContainerHighest color.surface.overlay
outline / outlineVariant color.border.default / color.border.subtle
shadow / scrim color.shadow / color.scrim
inverseSurface / onInverseSurface color.text.primary / color.surface.canvas
inversePrimary color.accent.subtle

Further theme fields: scaffoldBackgroundColor and canvasColor color.surface.canvas, dividerColor color.border.subtle, hoverColor color.surface.hover, focusColor and the focus ring of filled, elevated, text and outlined buttons and of focused inputs color.focus.ring (DsAccent.focusRing) with border-width.focus (focus is always visible, docs/design/components.md); outlined buttons otherwise color.border.control with border-width.hairline. visualDensity: comfortable gives VisualDensity.comfortable, compact VisualDensity.compact, touch VisualDensity.standard. Text theme: display roles type.display; headline and titleLarge type.title; titleMedium type.heading; titleSmall, labelLarge and labelMedium type.label; bodyLarge and bodyMedium type.body; bodySmall type.body-sm; labelSmall type.caption; colored with color.text.primary. Under reduced motion every platform uses DsNoTransitionsBuilder.

Fonts

fonts/ holds the variable TTF files of Atkinson Hyperlegible Next and Mono (upright and italic, axis wght) and the OFL text of each family; fonts/MANIFEST.json records source, commit, SHA-256 and license per file, and test/fonts_test.dart checks them (docs/DECISIONS.md D-M4-04-4, docs/quality/licenses.md "Bundled fonts"). Inside this package the families resolve under their plain names; an app that depends on the package registers them as packages/design_system/<family>, which dsTextStyle puts in front of the fallback list.

To move to a newer upstream state: download the four files from fonts/variable/ and OFL.txt of both repositories at the new commit, store them under the names of fonts/, update fonts/MANIFEST.json (source, commit, sha256, bytes) and run the tests. Every file stays below repo.max_file_kb.

Icons

DsIcon(DsIcons.<name>, label: ...) draws a semantic icon; the glyph and its weight come from design/tokens/icon.tokens.json, never from a Phosphor name in widget code (docs/design/icons.md "Rules"). filled: true draws the fill form (active, reached state); size is DsIconSizeRole.sm, md (default) or lg; the color defaults to color.text.primary. Every icon needs a non-empty label (read by the screen reader as an image) or decorative: true (excluded from semantics); otherwise the constructor throws an ArgumentError. trigger.working, run.running and state.reconnecting rotate once per motion.duration.pulse in full motion and stand still in reduced motion.

The assets are generated (docs/design/icons.md "Integration (M4-05)"): assets/icons/<weight>/<glyph>.vec compiled from the vendored Phosphor SVGs by uv run tools/design-tokens/tokens.py icons (also part of build), with assets/icons/LICENSE (Phosphor, MIT) and assets/icons/MANIFEST.json (source and asset SHA-256, total size). Never edit them; a new icon is a change in icon.tokens.json, then tokens.py vendor when its SVG is not vendored yet, then build. test/icons_complete_test.dart checks that every semantic and space icon resolves and the golden test/goldens/icons_test.dart shows every semantic icon in its mapped weight and in fill.

Tokens

lib/src/generated/design_tokens.g.dart is generated: never edit it. Change design/tokens/ and run uv run tools/design-tokens/tokens.py build from the repository root, which writes this copy and design/build/dart/design_tokens.g.dart with the same bytes; make tokens fails when they differ (docs/DECISIONS.md D-M4-04-1).

Golden tests

test/flutter_test_config.dart loads the bundled fonts and configures alchemist: CI goldens (text as blocks, Ahem) run on every machine; platform goldens with the real fonts run only on macOS (docs/spec/15-client-architecture.md 20). Golden tests live in test/goldens/, their images in test/goldens/ci/ and test/goldens/macos/. Another member copies the same flutter_test_config.dart, keeps alchemist as a dev dependency and builds its matrix with dsGoldenMatrix (docs/DECISIONS.md D-M4-04-5).

Regenerate goldens after an intended visual change with flutter test --update-goldens in the package folder. Platform goldens are updated only on macOS; on another system the command rewrites only the CI goldens.

Dependencies

Allowed members (docs/spec/15-client-architecture.md, 3.1; tools/arch-check/rules.yaml): l10n, domain (arrows of the diagram). Every other member is out of reach; make arch fails on a dependency or an import of it. External: markdown (BSD-3-Clause) parses message Markdown into an AST, rendered by the own widgets of DsMarkdown (docs/DECISIONS.md D-M4-07-2); alchemist (MIT) as a regular dependency, because testing.dart returns its GoldenTestGroup (docs/DECISIONS.md D-M4-04-5); flutter_test (SDK) as a regular dependency for dsPumpIcons; vector_graphics (BSD-3-Clause) renders the icons; crypto as a dev dependency for the font check; vector_graphics_compiler (BSD-3-Clause) as a dev dependency that tokens.py icons runs from the workspace lock.

Further rules checked by make arch:

  • no native source (rule 4).

Layout

Path Content
lib/design_system.dart the public library; every public symbol has a doc comment (make lint, public_member_api_docs)
lib/testing.dart golden helpers for tests of every member
lib/src/generated/ the generated token copy and icon lookup (no doc lint, no format check, no coverage)
lib/src/icons/ DsIcon
lib/src/components/ the core components, their view models and the Markdown renderer
assets/icons/ generated icon assets, Phosphor MIT text, MANIFEST.json
lib/src/theme/ context, resolver, theme builder, scope widget
fonts/ bundled font files, OFL texts, MANIFEST.json
test/ tests, run by make test with coverage (quality.coverage.dart_min_percent)

Run from the repository root: make lint test coverage arch COMPONENTS=apps. The API pages come from make docs (Dart API reference).

Libraries

design_system
Design tokens (generated), theme, components, icons and fonts of the apps.
testing
Golden test helpers shared by every member that renders design-system widgets.