Design system
AgentUp.DesignSystem/ is the single source of truth for Agent-Up product UI, documentation, and marketing. Canonical HTML and CSS compile to the bindings Desktop and Mobile consume.
The public showcase is available at /design-system. It is linked
from the site navbar and footer. The page opens with the contract intro beside a
live collage of catalog product-control examples in a two-column view that crops
overflow so the hero stays filled. The right-hand view is taller than the
visible area on purpose: extra catalog controls, including a Git history
timeline, pack the columns and clip at the bottom rather than leaving empty
canvas. Those examples are the same
component.html definitions as the catalog below, parameterised with
data-au-props, so the intro stays in sync when the catalog changes. Assembled Desktop and Mobile screens follow, selected
by a horizontal chip strip. Those views mount assembled screen HTML: src/screens.html layouts that
data-au-use catalog component ids. The heading, chip selection, and Desktop
and Mobile pair share one centered max-content block so page zoom recedes them
together. Each scene lays out at native pixels, then scales into one shared
display height so Desktop and Mobile stay matched and the whole window stays
visible. They do not embed persisted PNGs and they
do not restate component markup. Below that, a vertical
surface list sits in the left of the content column, and each selected surface
shows the live components that surface uses.
Ownership and sources
src/agent-up.cssowns semantic colors, typography, spacing, shape, accessibility defaults, layout primitives, and reusable interface components.src/product.cssowns Agent-Up product surfaces such as chrome, workspaces, application tabs, browser, console, Git, diagnostics, metrics, validation, sign-in, and Mobile.src/catalog.htmlowns the shared HTML structure Desktop, Mobile, docs, and the showcase infer from. A component is authored once and parameterised rather than copied:data-au-statesdeclares a selection group or a flag,data-au-partsanddata-au-textdeclare an optional control and a piece of copy, anddata-au-state-examples/data-au-props-examplesgenerate the catalog's documented variations from that one piece of markup. A scene sets them withdata-au-stateanddata-au-props. Before this a state was a second component with its own copy of the markup, which is how four tab strips differing only in which button carried--selectedcost four copies of the same five buttons.data-au-modifier-classesnames the Desktop class a modifier maps to, so naming one no longer needs a component of its own. Surface-specific fragments such assrc/catalog-git-log.htmlandsrc/catalog-file-viewer.htmlare concatenated at build time so Git history and file inspection can evolve without colliding with the working-tree catalog. Avalonia control types and Desktop class aliases are declared on each catalog example.src/git-log.cssowns the Git history graph, pinned timestamp column, sticky selected detail, and ref chips. Lane colors are the--au-color-git-lane-*tokens insrc/agent-up.css.src/file-viewer.cssowns the readonly inspection window: header, hunk navigation, gutter, line kinds, and syntax token colors. Grammars live insrc/syntax/highlight.mjsand compile to Mobile and Desktop.src/docs.cssowns documentation structure (kicker, focus, what-it-is, numbered spine, contract, fork, facts, surface rows, steps, callout, next). It is not compiled into Desktop or Mobile bindings.src/marketing.cssowns campaign and product-frame compositions.src/screenshots/shell.cssowns the showcase embed: a centered heading, selection, and pair that lays each scene out at native pixels then scales both frames to one display height. It must not stretch to the viewport or scale with container-query units, because those leave the frame behind when the page zooms. Screen chrome layout lives insrc/product.cssas.au-screen*so Desktop can apply the same classes.src/icons.htmlowns every product icon, as stroked path geometry on a 24x24 grid.scripts/lib/icons.mjsinlines it wherever the catalog or a screen writesdata-au-icon, and emits the same geometry asdist/web/icons.json,dist/native/icons.jsfor react-native-svg, anddist/dotnet/AgentUpIcons.g.csfor AvaloniaStreamGeometry. Desktop draws Unicode glyphs and Mobile names Ionicons today; those two surfaces adopting the emitted geometry is what makes a documented screen match a real one at the icon level.src/screens.htmlowns assembled screens: named layouts plus scenes that fill regions withdata-au-useof catalog component ids, including thescreen*layout shells.scripts/lib/screens.mjsinserts leaf catalog HTML and applies empty layout shells as wrappers. Persist writes the result intomedia/. Thescreen*shells and the Demo fixtures are web-only (webOnlyinscripts/lib/css.mjs): a Border carries no flex model and Desktop builds its shell from Grid, so emitting them produced bindings no surface could use.- Scene documents link
../screenshots.cssrather than inlining it. Twenty-two copies of the same stylesheet made the committed output almost entirely one repeated file; Chromium resolves the sibling overfile://exactly as it resolves the document. brand/voice.jsonowns product naming, positioning, capability lifecycle language, and editorial principles.scripts/build.mjsdeterministically copies web assets and compiles the CSS custom properties and class rules into React Native objects and Avalonia resources plus styles underdist/.
Files under AgentUp.DesignSystem/dist/ are generated definition artifacts. Do
not edit them directly. Change the canonical CSS or HTML catalog, run
./au-debug build design-system, and review every consumer.
Consumer boundaries
The documentation site imports the CSS package directly. Mobile imports
agentUpTheme, auBox, and auText from @agent-up/design-system/native
and applies those compiled component styles to chrome, rows, cards, buttons,
and fields. Mobile must not invent a second look from color tokens. Desktop
includes the generated AgentUpTheme.axaml resource dictionary and
AgentUpStyles.axaml style sheet. Desktop applies catalog classes such as
wsEntry, au-sign-in, and au-button instead of restating fill, radius, and
border as local XAML. It keeps only ControlTemplates or optical adjustments
that CSS cannot express.
These are hard dependencies rather than examples copied into each project. A change to the canonical CSS or catalog is incomplete until all generated bindings are current and the Desktop, Mobile, docs, design showcase, and marketing-template checks pass.
Visual rules
Desktop is the reference rendering:
- Near-black (
#0a0b0c) is the canvas. Desktop rails and the Mobile drawer stay on that canvas. Surfaces step up throughsurface/surface-raised/surface-overlayso cards, fields, and overlays read as containers rather than vanishing into the page. - A tappable card, such as an agent picker row, is
.au-choice. It is a catalog Button that already paints as a card, including hover and disabled opacity. Do not wrap.au-cardin a platform Button. - Agent replies are
.au-card. Tools and other in-run steps are.au-chat-workon the quieter surface. The human prompt is.au-chat-user: a right-aligned selected surface sized to the text. Finished work between questions collapses to.au-chat-run; the trailing agent reply stays visible. Nested thoughts stay.au-chat-thought. Do not put thoughts or tool rows in a result card. - Borders are alpha hairlines, not fixed grays. An opaque border reads about 2.4x stronger on the canvas than on a raised surface; alpha composites, so one token keeps an even weight across the whole ramp. A product drawn mostly in borders reads as a wireframe grid of rectangles.
- Interaction is neutral. Hover and pressed use
state-hoverandstate-active— white at 6% and 10%. Painting the brand colour into every interaction state is the Material signature and is forbidden; a test enforces it. An element that already rests on the accent may brighten it on hover. - Selection is meaning. A selected row takes the accent tint plus a 2px accent rule on its leading edge. Saturated accent fills behind text are retired: muted text on the old fill measured 1.83:1.
- Emphasis follows the information hierarchy. The primary selection on a screen carries the accent — choosing an application is a 2px accent underline. Secondary selections, and many-of-many filter sets, stay neutral.
- The Git change list is
.au-git-change-listwith.au-git-rowrows. Filenames are.au-git-change-name(directories use--directory). Status glyphs are.au-git-statuswith--added,--untracked,--deleted,--modified,--renamed,--conflicted, and--directory. Directory depth uses.au-git-tree-guidehairlines and.au-git-tree-togglechevrons (--expanded/--collapsed). Checkbox selection stays on the checkbox; the open file uses--selected. Do not color the filename with the change kind. Review counts use.au-git-insertionsand.au-git-deletions. Counts on a primary Commit button use--on-primaryso they take on-accent instead of accent-on-accent. - Git history is
.au-git-logwith.au-git-log-rowentries, a pinned.au-git-log-timecolumn,.au-git-log-graphlanes in.au-git-log-graph-scroll, and a sticky.au-git-log-detailheader for the selected commit. Ref chips stay in that header. Lanes use--au-color-git-lane-*. Do not render ASCII| * |glyphs. - Validation is
.au-validation-sidebar, a right rail on the selected application, not a full-screen pane..au-validation-flowcards nest.au-validation-stagegreater steps and.au-validation-checkmicro-checks. Glyphs use.au-validation-glyphwith--passed,--running, and--failed; pending stays muted. Play is.au-validation-play, a selected-strong pill. Collapse uses.au-workspace-add. Do not paint a stage as a fat status card. The default rail is.au-validation-sidebar--collapsed. - File inspection is
.au-file-viewer: a readonly overlay with.au-file-viewer-header(path + status),.au-file-viewer-navhunk jumps,.au-file-viewer-linerows, and.au-syntax-*tokens. Added lines use the selected-soft fill; deleted lines use the danger surface; the current line uses the selected tint plus a 2px accent rule. Code is preformatted so leading spaces and tabs stay visible. Do not dump a file into one text node, and do not paint syntax with accent green. - Radius scales with the object:
xs/smfor controls,mdfor rows, buttons and inputs,lgfor panels and cards,xlfor panes and dialogs. An 8px corner reads rounded on a chip and square on a 900px pane. - Working regions are
.au-pane— inset on the canvas with a container radius and one elevation step — not full-bleed panels butted together at 1px lines. Dialogs and menus use.au-overlay-panelabove a scrim. The sign-in screen is a compact pane on the canvas (.au-sign-in), not an overlay. Saved-server URLs ellipsize (.au-choice-label) with the full URL in the tooltip, and the saved list (.au-sign-in-list) scrolls. Rows do not display credential state; selecting a saved server applies a stored sign-in. - Product chrome uses the UI type tier (
--au-font-size-ui-*, 11-22px) and the UI weight roles (--au-weight-ui500,--au-weight-ui-strong600). The content tier and 700+ weights belong to docs and marketing; uniform 700 on 11-13px labels is what reads as a template. Product screens use.au-page-titleand.au-field-label, not marketing display type. - Any surface made of digits — logs, tables, ports, timestamps, metrics — sets
font-variant-numeric: tabular-numsso columns align. - Off-white and muted gray-green establish text hierarchy. Every text role must clear WCAG AA on every fill the catalog puts it on; a test enforces it.
- Blue focus remains distinct from green success.
- Red identifies errors, failures, and destructive actions.
- Ambient neon glow, decorative green grids, green borders around every surface, and accent-tinted hover states are retired.
- Product UI and design-system product screenshots are preferred to speculative
illustrations. Persist those shots with
au-debug screenshots persist; do not reconstruct Desktop or Mobile chrome in docs HTML. The marketing homepage is a left lockup plus.au-feature-cardtiles on the right. The lockup title stays on one line and sits beside a 3x3 grid that fits a 1440x900 viewport at 100% zoom, vertically centered with that grid. Feature tiles center the relevant catalog component, with preview sample data, in a fixed inset viewport instead of stretching a screenshot crop, and use one short.au-mutedline instead of a subtitle. A click opens Desktop and Mobile shots together in.au-feature-modal, portaled todocument.bodyso it stays a viewport overlay. The connect pane is the Multi-server tile. File viewer and other tooling overlays stay out of that grid.
Mobile uses the same sign-in pane, workspace row, and type scale as Desktop.
Primary actions stay 44px; chrome stays compact. Documentation prioritizes
reading. Marketing gets one focal point, one outcome, and a visible
Available, Preview, Experimental, or Planned label when it describes a
capability.
Commands
npm --prefix AgentUp.DesignSystem run build
npm --prefix AgentUp.DesignSystem run check
npm --prefix AgentUp.DesignSystem test
The check command fails when a generated web, React Native, or Avalonia binding
does not exactly match the canonical HTML and CSS. Native font-style compiles to
React Native italic or normal; CSS oblique maps to italic because React
Native does not accept oblique. Native font-family is omitted: CSS stacks are
not React Native font names, and a linked Expo Font module treats an unknown
family as a production fatal instead of falling back to the system face. A catalog
class whose remaining declarations are all omitted, such as .au-mono, still
registers an empty native style so auText('mono') does not throw. Multi-value
border-radius, white-space, and ch lengths are also omitted or reduced to a
single pixel radius so Fabric does not abort on a string where it expects a number.
Screenshot HTML is generated in the same build from src/screens.html;
refresh media/ with au-debug screenshots persist and prove the shots still
compose catalog component HTML with au-debug screenshots validate.