@xmesh/system-design
v0.5.1
Published
Design-system reference and Lit component library for the xmesh chat product.
Maintainers
Readme
xmesh Design System
A design system extracted from the xmesh chat product — a desktop AI-chat
shell with smart routing, agent traces, and a settings drawer for editing
agent definitions. The system is built around a warm dark canvas with white
card surfaces and a coral accent (#cc785c, ~40°), theme-flippable to a cream-light
mode.
Strict editing rules live in POLICIES.md. The visual
target — palette, type, surface ramp, voice, anti-patterns — is documented
in this file (sections CONTENT FUNDAMENTALS, VISUAL FOUNDATIONS,
ICONOGRAPHY below); the token catalogue with one-line roles per token is
in styles/README.md.
Sources
This system was built from the following materials:
| Source | Path / link | Notes |
| --- | --- | --- |
| Source codebase | sergeytkachenko/langgraph_smart_routing (GitHub) | LangGraph-based smart-routing agent platform |
| Existing docs / system | docs/desing-system/ (in repo, in the original tree — note the typo desing) | Tokens, themes, components, preview canvas |
| Chat composition components | packages/shared/components/chat/latest/ | Live composer / sidebar / message list |
| Reference screenshot | docs/desing-system/uploads/chat_desired_styles.jpg | Canonical composer styling |
The original docs/desing-system/ folder (with its typo) lives in the source
repo only — it is not carried into this repo. This design-system folder is
the published + cleaned version, now migrated to canonical Material
Design 3 at the role tier (--md-sys-color-*, --md-sys-typescale-*,
--md-sys-shape-corner-*, --md-sys-elevation-level*, --md-sys-motion-*).
xmesh-specific concepts that have no MD3 home (mono typescale, categorical
badges, paper artboard, snackbar scrim, drawer shadow, focus ring) live
under the --xm-* namespace. Spacing stays as the xmesh --s-N 4px
primitive scale (MD3 has no spacing scale). The legacy --c-* / --t-* /
--r-* / --e-* / --m-* namespaces survive in styles/_semantic.css
etc. as transitional aliases that delete in the lockdown phase. Primitives
(--x-*) feed the MD3 layer once and are not referenced from components.
Index
| File / folder | Purpose |
| --- | --- |
| styles/ | The real token system, split by responsibility (_primitives.css, _semantic.css, _type.css, _space.css, _elevation.css, _fonts.css, _scroll.css), wired by styles/index.css. Token catalogue in styles/README.md. |
| colors_and_type.css | Back-compat shim — only does @import "./styles/index.css". Kept so older HTML keeps working. |
| assets/ | Brand mark + lockups (SVG only). |
| fonts/ | Intentionally empty — Inter and JetBrains Mono pull from Google Fonts via _fonts.css. |
| lit/components/ | One folder per component, each with index.css + index.ts: artifact, brand-mark, bubble, button, chat, composer, primitives, sidebar-item, snackbar, validation. TS is the canonical source. Each component exposes a custom element named xm-<name>. lit/components/types/ holds shared .d.ts shims (Lit-from-esm.sh re-export). |
| lit/preview/ | Cards rendered on the Design System tab (one concept each). Loads card.css for the page scaffold, _shell.{css,js} for the page chrome and xmesh.mount() helper, and theme-toggle.js for dark/light persistence. |
| lit/build/ | Compiled .js, mirrors lit/components/. Git-ignored — produced by tsc. Previews <script type="module">-load from here. |
| scripts/ | Lint/check scripts (check-tokens.sh, check-structure.sh, check-previews.sh, check-bem.sh, plus the check.sh wrapper) and screenshot.mjs (Playwright). |
| package.json | npm scripts: serve (tsc-watch + http-server), build:lit / watch:lit, screenshot / shoot-all, check[:tokens\|:structure\|:previews\|:bem]. Runtime devDeps: typescript, npm-run-all, lit (types only), playwright, http-server. |
| SKILL.md | Agent-skill manifest, makes this package usable as a Claude Code skill. |
Earlier React port removed. Until recently this repo also shipped a React port at
components/+preview/(JSX-as-canonical-source, no build step). Commits91da854(split intoreact/+lit/),6f68d05(move React side tolegacy-react/), and4b2d9ba(deletelegacy-react/) retired it. References below to JSX components are historical context only — the live tree islit/.
Use this in another site
Two ways to consume, depending on what you need: the tokens only (any
site), or the tokens + Lit components as the npm package
@xmesh/system-design (bundler-based projects).
Tokens only (any site)
The public entry point is styles/index.css. It pulls in fonts,
primitives, semantic tokens, type, spacing, elevation, and the legacy
shim — everything a consuming site needs.
/* in your site's global CSS */
@import "path/to/xmesh-system-design/styles/index.css";
:root { /* default = dark theme */ }
:root[data-theme="light"] { /* set on <html> to flip */ }Reference only the documented tiers:
| Tier | Prefix | What it is |
| --- | --- | --- |
| Color (MD3) | --md-sys-color-* | Surface ramp, on-* roles, primary/secondary/error, outline. Canonical Material Design 3. |
| Color (xmesh ext) | --xm-color-*, --xm-method-*, --xm-ext-* | Categorical badges, paper, on-surface third tier, primary-pressed. Non-MD3 concepts. |
| Type | --md-sys-typescale-* | 15 MD3 type roles × 5 sub-tokens. Composite shorthands --t-* for legacy callsites. |
| Radius | --md-sys-shape-corner-* | extra-small, small, button, medium, large, extra-large, full |
| Spacing | --s-1 … --s-12 | 4px-base scale (xmesh primitive — MD3 has no spacing scale). |
| Elevation | --md-sys-elevation-level0..5 | Shadows. xmesh-specific drawer/snackbar/focus-ring under --xm-*. |
| Motion | --md-sys-motion-duration-* / -easing-* | MD3 duration scale + 7 easing curves. |
Never reference --x-* — those are primitives, used by _semantic.css
internally. Components and consuming sites use the semantic tier.
The full token catalogue with one-line roles is in styles/README.md.
Tokens + Lit components (npm package)
To consume the actual <xm-*> components in a bundler-based project
(Vite / webpack 5), install the published package and the lit peer:
npm install @xmesh/system-design litThe package ships the prebuilt ESM bundle (dist/lit/, co-located CSS, and
.d.ts) — it's built at publish time, so there's nothing to compile on
install. Then, once at app root:
import "@xmesh/system-design/styles"; // tokens → :root (required, once, before first paint)
import "@xmesh/system-design/lit"; // registers every <xm-*> element
document.documentElement.dataset.theme = "dark"; // or "light"
// or tree-shaken: import "@xmesh/system-design/lit/button";<xm-button variant="primary">Send</xm-button>The full consumer guide (subpath imports, TypeScript types, version pinning,
and using the web components inside React/Vue/Angular) is in
lit/README.md; the
rationale and the build/distribution decisions are in
ADR 0004 (now
superseded by ADR 0007).
Visual feedback for Claude Code
npm run screenshot <preview.html> renders any preview in dark + light
themes via Playwright and writes PNGs to screenshots/. Claude Code's
Read tool can open those PNGs directly. Use npm run shoot-all to
regenerate every preview's screenshot set.
npm run check runs four deterministic guards (see scripts/):
check:tokens—lit/components/*/index.cssfor raw hex /oklch()/rgb()/hsl()literals,--x-*primitive references that bypass the semantic tier, and the deleted legacy--p-*/--s-{surface,…}-*aliases.check:structure— every component islit/components/<name>/index.{css,ts}, no other.css/.tssiblings in the same folder, withlit/components/types/exempt for the shared Lit-CDN.d.tsshim.check:previews— everylit/preview/*.htmlimportscard.cssandtheme-toggle.js, and no<link>/<script>URL uses?v=*cache-busting (POLICIES.md rule 12a).check:bem— strict BEM inlit/components/*/index.css:block,block__element,block--modifier; state classes (.is-*,.has-*) must combine with a block; no bare tag selectors; no cross-block descendant chains except those allow-listed inscripts/check-bem.sh.
Each sub-check is also runnable individually:
npm run check:tokens / :structure / :previews / :bem. Run
npm run check before committing.
The strict rules enforced by these checks (and the manual ones that aren't) are documented in POLICIES.md.
Brand at a glance
xmesh is a single-product desktop chat for an AI agent platform. It feels like a sturdy, opinionated tool: a craftsman's terminal more than a SaaS landing page. The mood is warm, not cool (coral accent, oklch hues biased toward 40–80°), dense, not airy (small type, tight gutters, lots of hairline borders), and functional, not decorative (no gradients, no illustrations, almost no emoji).
Two themes ship: dark (default — warm desaturated near-black canvas with
lifted dark cards) and light (cream canvas with white cards and dark ink).
The card stack follows the theme rather than staying white in both (ADR 0006).
A black theme is referenced in the source for AMOLED contexts.
CONTENT FUNDAMENTALS
Voice
Direct and operational. Copy describes what the surface does or what state it is in, not how the user should feel. Examples from the source:
- File picker hint:
"Choose file or drop here"/"YAML or JSON · up to 200 KB" - Composer footer:
"Enter to send · Shift+Enter for new line" - Counter:
"4127 / 5000"(raw numbers, no "characters used:") - Processing state:
"Routing query through Planning Path…" - Stop hint:
"Click ▢ to cancel current request"
- File picker hint:
System-as-narrator, not assistant. Status strings describe the system in third person —
"Routing query through Planning Path…", not "I'll route this for you."Validation titles are blunt nouns. From
lit/components/validation/index.ts(theVALIDATION_TITLEexport):"File too large","Wrong file type","Couldn't parse file","Unexpected structure","Empty file","Read error". No exclamation marks, no apologies, no "Oops!".
Casing
Sentence case for everything. UI labels, buttons, headings, drawer titles — all sentence case.
"New chat","Cancel current request","Routing query through Planning Path…". Title Case is reserved for proper nouns ("Planning Path","REST","GraphQL").Caps for tech identifiers:
YAML,JSON,REST,GraphQL,KB.No ALL-CAPS as styling. The eyebrow type ramp uses uppercase + tracked letter-spacing, but the underlying string in source is sentence case.
Pronouns
- Imperative, no I/you in inline copy. "Choose file or drop here", not "You can choose…". The product never says "I".
- Second-person ("you") only in long help/empty-state body copy — kept rare.
Typography of copy
- Numbers + units side by side:
"412 KB","200 KB","4127 / 5000". Use a normal space between number and unit. - Keyboard hints:
Enter,Shift+Enter,⌘K— rendered as small kbd pills, not bracketed. - Middots (
·) separate inline metadata:"Enter to send · Shift+Enter for new line","8.4 KB · 4 agents, 12 tools". Em-dashes (—) join clauses inside a single string. - Ellipsis is a single character (
…), not three dots. Used at the end of pending state strings.
Emoji & emotional tone
- No emoji in product UI. The brand mark is geometric. The composer's send button is an arrow glyph; the stop button is a filled square. Status uses small dot indicators, not emoji.
- Tone is matter-of-fact. Errors describe the failure with the data
(
"File is 412 KB. Maximum allowed size is 200 KB.") instead of softening it. No "oops" / "uh-oh" / smiley — but also no scolding.
Vibe summary
If xmesh copy were a person it would be a senior infra engineer leaving a helpful comment in a PR: short, technical, no fluff, occasionally dry, never cute.
VISUAL FOUNDATIONS
Color
- Two surface families — the
surfacedesk (--md-sys-color-surface, warm near-blackoklch(0.21 0.003 60)in dark, cream in light) and theinverse-surfacecard stack. The card stack is theme-following (ADR 0006): a lifted dark surface in dark theme, white in light. Every component sits on exactly one. Sidebar + chat list ridesurface; cards, drawers, popovers, composer field rideinverse-surface. Container tiers (surface-container-{lowest,low,…,highest}) step the desk up for hover, raised chrome, dialog elevation. - Single accent: coral, hue ~40°,
#cc785c(oklch0.62 0.110 40), exposed as--md-sys-color-primary. Used for primary buttons, focus rings, the brand mark, the character counter when near limit, and the user-message bubble in light theme. Never used for decoration; always functional. - No saturated brand color. No blues, no purples, no neon greens. The
only saturated hues are the categorical badge sets — HTTP-method
pills (
GET~220°,POST~145°,PUT~70°,DELETE~25°,PATCH~290°) and file-extension pills (YAML~70°,JSON~145°). These signal category, not severity. There is no status-pastel family any more: severity (errors / warnings / info / success) is communicated by icon shape + label, not by color. - Hue discipline. Almost everything sits between
45°–80°(warm) or exact neutrals. Cool hues only appear in the categorical badge sets noted above.
Type
- Inter for UI, with
font-feature-settings: "ss01", "cv11"enabled (the alternate-1 and stylistic-set 1 keep numbers and capitalidistinguishable in dense lists). - JetBrains Mono for code, file paths, JSON pointers, error rules, char counters when shown as raw values.
- Three weights only: 400 (body), 500 (medium — labels, chips), 600 (semibold — titles and button text). 700 used sparingly; never italic.
- Tight scale: body is 14px, small is 12px, eyebrow is 11px. Display only
goes up to ~34px (
h1); the chat product itself rarely uses anything over 18px. Letter-spacing is negative above 18px (-0.01emto-0.02em) and zero below.
Spacing & layout
- 4px base grid (
--s-1through--s-12). Most chrome lives at 12–24px; card padding is22px 24px 14pxfor headers,14px 24px 18pxfor footers. - Three-column shell: 280px sidebar, 1fr chat, optional drawer slides over the right edge of the chat pane (absolute-positioned overlay, not a third grid column).
- Compact mode collapses sidebar to a 60px icon rail. Drawer-in-narrow hides the sidebar entirely (used for the trace-drawer demo).
- Hairline borders (1px, low-saturation) do most of the separation work. Cards rely on subtle inner-line shadow + tiny outer drop, not heavy elevation.
Backgrounds
- No imagery, no full-bleed photos, no patterns. The canvas is a flat
warm-near-black; the surface is flat white. The only "texture" is the
optional dot-grid on the design-canvas wrapper (
--s-dc-grid), which sits outside the chat product itself. - No gradients in product UI. A single intentional gradient appears in
the snackbar overlay (
--c-snk-overlay/-strong/-softthree-stop vertical fade) because GPU blur was rejected.
Animation & easing
- Fast, restrained, almost-no-bounce. The base timing is 120–160ms
with
ease. Hover transitions on chrome are 120ms; theme-swap fade is 220ms. There are no spring/bounce easings, no scale-up reveals, no attention-grabbing motion. - Reduced motion:
*::-webkit-scrollbar-thumb { transition: none; }underprefers-reduced-motion— the source explicitly cuts thumb transitions for that audience. - Status indicators use a slow pulsing dot (the
…in the thinking-status row), not spinners.
Hover & press states
- Hover: warm up the surface by one step. Sidebar items go from
--c-sidebarto--c-sidebar-hover. Buttons darken from--c-accentto--c-accent-strong. Borders gain--c-border-strongon hover. No brightness/filter tricks, always real token swaps. - Press / pressed: inset shadow
--e-pressed(very subtle inner top line), no scale change. The "active" sidebar chat item also picks upinset 0 0 0 1px var(--c-border-canvas)to read as pinned. - Focus:
box-shadow: var(--e-focus-ring)— a 1px halo of--c-accent-soft. Outlines are removed in favor of this.
Borders, radii, corners
- Radii:
8pxchip /10pxfield+button /14pxcard /999pxpill. No 0-radius hard corners, no 20px+ pillowy radii. Buttons and inputs share10pxso they snap together. - Borders are 1px, hairline. The focus ring is also a 1px halo. 2px
borders only appear in the drag-active state of artboards on the
design-canvas chrome (
--s-dc-shadow-card-dragadds a 2px accent ring).
Shadow / elevation system
Six layers, semantic names:
| Token | Used for |
| --- | --- |
| --e-subtle | Inline chips, file rows |
| --e-subtle-md | Slightly raised badges |
| --e-card | The composer / drawers (combo: 1px brightening top edge + soft 24px drop) |
| --e-popover | Menus, tooltips |
| --e-popover-strong | Modals |
| --e-snackbar | Snackbar card (top inner highlight + 18px + 4px stack) |
| --e-drawer | Right-side slide-in trace drawer (left-cast shadow -16px 0 40px) |
| --e-pressed / --e-pressed-soft | Inset top line for pressed/active rows |
| --e-focus-ring | 1px halo of --c-accent-soft |
Inner shadows are reserved for pressed states and the card top edge (brightening line). No shadows on the canvas itself; the canvas is the ground.
Transparency & blur
- Blur is avoided. The snackbar overlay explicitly chose a vertical
gradient over
backdrop-filterfor performance; this is documented in the source comment. - Transparency appears in: focus rings (1px alpha halo), scrollbar thumbs (alpha-on-canvas), shadow stacks. Solid surfaces are otherwise solid.
Imagery
- There is no imagery. No photos, no illustrations, no animated avatars. The only visuals are: the brand glyph, monochrome line icons, and flat color fills.
Card anatomy
A typical card (composer, drawer, modal) uses:
background: var(--c-card)(the theme-following card-stack surface)border: 1px solid var(--c-border-subtle)(hairline)border-radius: var(--r-card)(14px)box-shadow: var(--e-card)(combo top-line + soft drop)padding: 22px 24px 14px(header) /14px 24px 18px(footer)- Header / footer are separated by
1px solid var(--c-border-subtle)rather than padding alone.
ICONOGRAPHY
Approach
xmesh draws all icons as inline SVG at 16–24px with currentColor and
inline sizing. There are two idioms (see ADR 0017):
- Legacy Lucide-style line icons —
stroke-width1.8–2.4,currentColorstrokes, rounded line caps, no fills. Defined inline inside the Lit primitives module (lit/components/primitives/index.tsexports the namedxm-*-iconelements; per-component icon sets — e.g. validation's status glyphs — live alongside their owning component). - Google Material Symbols (Outlined) — fill-based glyphs rendered by name
via
<xm-icon name="…">(lit/components/icon/index.ts). The glyph path data is bundled in that module keyed by Material Symbol name, so there is no icon font, no sprite sheet, no runtime fetch. New glyphs come from this set.
Either way there is no external icon library bundled with the product and no CDN dependency at runtime. The visual character of the line set matches the Lucide / Feather family; the Material Symbols Outlined weight is chosen to sit close to it. The Lucide-via-unpkg substitution below applies to the UI kit preview only; the production app ships each icon's geometry inline.
Specific patterns observed in source
<xm-icon size="..." stroke-width="1.8">is the canonical wrapper. Children are<path>/<circle>/<rect>with thestroke="currentColor" fill="none"defaults applied by the wrapper.- Common icons: alert (circle + ! line), close (X), copy (stacked rectangles), upload (arrow + tray), check (single polyline), chevrons, search, plus, settings gear.
- No emoji. Anywhere. Not in chat-list dot indicators, not in error states, not in empty states.
- Unicode glyphs are used sparingly as inline marks:
…(ellipsis at end of progress strings),·(middot in inline metadata),→and↑for send arrows when geometry is simple. The send button in the reference screenshot is a real↑arrow.
Logo & brand mark
The brand mark in the sidebar is a 32×32 rounded-square chip with a
geometric glyph stroked in --c-accent-ink, sitting on a soft
--c-accent-soft fill. The wordmark is Inter 600 at 16px,
letter-spacing: -0.01em. We have an SVG of this in assets/brand-mark.svg;
treat it as the canonical lockup.
File-format badges
A small set of branded uppercase chips appears next to file names:
| Token pair | Use |
| --- | --- |
| --c-ext-yml-bg / --c-ext-yml-ink | YML / YAML files |
| --c-ext-json-bg / --c-ext-json-ink | JSON files |
These are used by <xm-file-validation-block> and any list of
agent-definition files. Add new ones by following the same _bg / _ink
pattern (warm hue, low chroma in dark, pastel-on-white in light).
HTTP method badges
Pre-themed pill backgrounds for GET / POST / PUT / PATCH / DELETE
exist (--c-method-*-bg / -ink); used in trace-drawer rows for tool calls
that hit external APIs.
CAVEATS
- Font files: the source repo references Inter and JetBrains Mono as
font-familystrings only — there are no.woff2files committed. The design system pulls them from Google Fonts at runtime. If you need an offline build, drop the.woff2files into/fonts/and replace the@importinstyles/_fonts.csswith@font-faceblocks. - Iconography: the production app inlines its own SVGs. References to a Lucide CDN substitution apply to the source repo's UI kit only — this repo ships no UI kit and no CDN icon dependency. Inline SVG line icons (Lucide style) when adding new components.
- No imagery / illustrations were found in the source — none have been invented.
docs/desing-system(sic): the original folder name has a typo and exists only in the source repo (sergeytkachenko/langgraph_smart_routing). It is not present in this repo; references to it here are for provenance only.- No
ui_kits/orslides/here. The source repo had a wired chat UI kit; this published system intentionally ships only tokens, components, and previews. If you need a full-app shell, fork from the source repo.
License
Apache License 2.0 © xmesh
