Oshun Platform · Features

Design System and Experience Quality

A focused page within the Oshun Platform Features documentation. The full map and every sibling page live in the Features hub.

9sections12 minread5tables

On this page

The Oshun V1 design system is the shared visual, behavioral, and copy foundation that every customer and admin surface is built on. It is not a style guide that lives in a deck — it ships as real, tested TypeScript: design tokens (libs/oshun/design-tokens), a reusable component library (libs/oshun/ui), the localization catalog (libs/oshun/i18n), and a suite of auditable design-language modules (libs/oshun/design-language) that encode the rules an engineer or reviewer can query and a test can enforce. This page sits in the platform-quality area alongside Analytics, Observability, Testing, and Security; together they describe how Oshun makes the product feel calm, consistent, accessible, and honest about AI. The companion architecture page is Architecture, Platform Foundations, and Security.

What the design system is, and where it lives#

V1 deliberately splits the design system into four cooperating packages so that "the rules" are independently testable from "the components" and from "the words":

Concern Package What it ships
Tokens (color, type, spacing, motion, behavior) libs/oshun/design-tokens oshunTokenSchema, themes, and behavior tokens
Reusable components libs/oshun/ui 21 React components plus motion/ and theme/ subpackages
Localized strings and formatting libs/oshun/i18n CUSTOMER_MESSAGES catalog, translate(), locale formatting
Design-language rules and audits libs/oshun/design-language scorecards, ergonomics, voice/tone, disclosure copy, visual-QA claims

The web app (apps/oshun/web) consumes all four: tokens drive its theme, @oshun/ui provides the components, next-intl wires the localized messages (apps/oshun/web/src/i18n/request.ts and apps/oshun/web/src/i18n/config.ts), and the design-language audits gate the design-review checklist.

Product language and information architecture#

V1 design begins with a single product thesis encoded in libs/oshun/design-language/src/index.ts as TARA_CENTERED_PRODUCT_LANGUAGE: "Oshun starts from Tara practice: calm attention first, then evidence, sky context, habits, texts, and learning." The voice is plain, source-aware, non-shaming, specific, and quietly confident; the prohibited registers are explicitly growth pressure, fear-led prompts, unattributed certainty, and operator jargon. This is not decorative prose — assertSurfaceUsesTaraLanguage() enforces that the home surface orders tara first and that headlines avoid growth-pressure language, so a surface that violates the thesis fails a test rather than merely a review.

The unified information architecture lives in OSHUN_UNIFIED_IA:

  • Customer shell: Home, Explore, Activity, Library, Assistant, Profile.
  • Admin shell: Queues, Review, Policy, Incidents, Privacy, Models, Personas, Support.
  • Journey models: morning Tara continuation, midday research-to-practice, evening sky-to-text, story-to-source, and assistant-led memory review.

The customer/admin shell distinction is also a visual distinction. The two visual theses in OSHUN_VISUAL_THESES describe the customer surface as "a quiet reading-and-practice workspace with Tara as the center, restrained chrome, clear evidence affordances, and mobile-first continuity," and the admin surface as "a dense operational console with scan-first hierarchy, hard audit edges, compact queue states, and restrained color." These two theses explain almost every density, color, and motion decision downstream — the customer shell trades density for calm; the admin shell trades calm for scan speed.

For the customer-facing IA itself (Tara, Arete, Veritas, Nyx, Nisaba, Metis and the cross-domain journeys), see the per-domain pages such as Tara — Rituals and Contemplative Practice and Nisaba — Scholarly Study; the shell-level surfaces are detailed in Product Surfaces.

Design tokens — the canonical foundation#

libs/oshun/design-tokens/src/tokens.ts is the single source of truth for the visual language. The canonical bundle is identified as OSHUN_V1_FOUNDATION_TOKEN_BUNDLE_ID = 'oshun-v1-foundation' at version OSHUN_V1_FOUNDATION_TOKEN_BUNDLE_VERSION = '1.0.0', exported as the oshunV1Foundation object.

Color#

The canonical V1 surface is a cool, dark ink/teal-and-gold system, not a warm paper palette. oshunTokenSchema.color is built from six full 50–950 scales:

Role Scale Anchor values
Neutral ink ink[500] = '#6E87A6', ink[950] = '#040B16'
Neutral fog fog[500] = '#7386A2', fog[950] = '#0D1628'
Brand aqua aqua[500] = '#20C9D8', aqua[600] = '#11A9B8'
Brand amber amber[500] = '#F4A524', amber[600] = '#DD8618'
Status success success[500] = '#2AB673'
Status danger danger[500] = '#E24D4D'

The default theme is dark: defaultOshunTheme = oshunThemes.dark, and oshunThemes provides all four named themes from OshunThemeNamelight, dark, highContrastLight, and highContrastDark. Theme resolution helpers (getSemanticTokens(), createCssVariables()) default to the dark theme, and a high-contrast resolver maps a "prefers high contrast" hint onto the highContrastLight/highContrastDark variants.

Correction to older docs. Earlier framing (e.g. V1/ARCHITECTURE.md around the Design System section) described the canonical surface as "cream-paper + terracotta." That is inverted. In the real tokens, cream-paper and terracotta are the manuscript palette used only for the domain accents, which the code itself describes as being "mapped into the Lilith register." The canonical neutrals/brand are the dark ink/fog and aqua/amber system above.

Domain accents (the "Lilith register" / manuscript palette)#

The domain accent hues live under oshunTokenSchema.color.domain (also exported as oshunDomainAccents), and the source comment explains the intent directly: each domain gets "a distinct hue from the manuscript palette … so the sidebar reads as the same cream-paper-and-ink language as the rest of the surface."

Domain Accent hex Manuscript name
tara #5A7A3F Lilith green
veritas #9A3E1C terracotta / burnt rust
nyx #3B3325 ink-2
arete #3F5E2B deep green
nisaba #C89657 honey / tan
metis #6B5A44 tan-brown

How these accents may be used is governed separately by oshunDomainAccentBehavior, so the accent is a constrained signal (sidebar, selection, domain header) rather than a free paint color. The translated contemplative variants are applied at the persona-policy boundary — see Lilith Persona Policy and Persona, Avatar, and Voice Packs.

Typography, spacing, motion, elevation#

The non-color foundation tokens are exported as first-class constants:

  • oshunSpacingScale — the numeric step scale that the semantic spacing tokens (xxs … 3xl) index into.
  • oshunFontWeights (regular, medium, semibold, bold, extrabold) and oshunTypographyRamp, with the type families Space Grotesk/Manrope (display), Manrope/Avenir Next (body), and IBM Plex Mono (mono). The ramp runs displayXl (48/56) down through labelSm and monoSm.
  • oshunMotionDurationScale and oshunMotionTokens (duration, easing, distance, scale) — motion is a token, so reduced-motion parity can be expressed by swapping tokens rather than rewriting components.
  • oshunElevationTokens — a named shadow ramp (none, xs, sm, md, lg, xl, inner).
  • Component radius ceilings: radius.sm = 8radius.pill = 999. The experience-quality rules pin an "8px component radius ceiling" so the system stays calm rather than bubbly.

Behavior tokens — the part most design systems leave to convention#

The distinctive part of design-tokens is that interaction behavior is itself tokenized, not just appearance. These exported behavior objects encode the rules for the trust-and-honesty surfaces V1 cares about most:

  • oshunGroundedEvidenceUiBehavior — how evidence cards, source counts, and confidence bands present (pairs with Sophia Grounding).
  • oshunDisclosureUiBehavior — where and how AI disclosure appears.
  • oshunAssistantPersonaSwitchingUiBehavior — how a persona switch is signaled.
  • oshunAvatarVoiceIdentityUiBehavior — avatar/voice identity affordances.
  • oshunTrustSignalUiBehavior — trust/confidence/provenance badges.
  • oshunReviewApprovalUiBehavior and oshunAdminStateUiBehavior — review decisions, approval states, queue/severity/SLA states for the admin console.

The component library (@oshun/ui)#

libs/oshun/ui/src/index.ts re-exports three subpackages: components/, motion/, and theme/. The component layer ships 21 real React components, not a placeholder barrel:

Group Components
Primitives Box, Stack, Text, Button, IconButton, Chip, Badge
Data display Card, ListRow, StatTile
Navigation TopBar, BottomNav, DomainSwitcher, CommandPalette
Feedback Banner, Toast, EmptyState, ErrorState
Overlays Modal, BottomSheet, ActionSheet

Each group has a paired .stories.tsx and .test.tsx (primitives, data-display, navigation, feedback, overlays), and the whole surface is exercised by accessibility-snapshots.test.tsx, which asserts the rendered accessibility tree — so a regression that strips an accessible name or focus affordance fails CI rather than slipping into a release.

Richer, domain-specific composites (evidence sidebar, claim/source/passage items, notebooks, collections, admin queues, policy diffs, avatar/voice cards) are tracked as catalog requirements (next section) and implemented across @oshun/ui and the web design-system package.

Design-language audit modules (@oshun/design-language)#

This package turns design rules into queryable, testable data — the mechanism that lets V1 claim design-system completeness without manually re-reading every component barrel. libs/oshun/design-language/src/index.ts re-exports ten audit modules, each versioned and each with a sibling .test.ts:

Module Key export What it encodes
component-catalog.ts OSHUN_COMPONENT_CATALOG (component-catalog-v1) Maps each required component to its canonical export, implementation path, test path, customer/admin scope, and required a11y checks
scorecards.ts OSHUN_SURFACE_SCORECARDS, OSHUN_IMMERSIVE_VS_INSTRUMENTAL Surface-by-surface quality scorecards; immersive-vs-instrumental guidance
ergonomics.ts OSHUN_THUMB_ZONE_MODEL, OSHUN_DENSITY_TIERS, OSHUN_ERGONOMIC_BUDGETS, OSHUN_ONE_HANDED_SURFACE_CONTRACTS One-handed mobile thumb zones, layout-density tiers, ergonomic budgets
responsive-system.ts OSHUN_BREAKPOINTS, OSHUN_CONTENT_MEASURE, OSHUN_READING_RHYTHM Grid/gutter/max-width, reading measure and rhythm
surface-language.ts OSHUN_IMAGERY_RULES, OSHUN_ILLUSTRATION_RULES, OSHUN_TEXTURE_RULES, OSHUN_AMBIENT_MEDIA_RULES, OSHUN_CARD_AVOIDANCE_RULES Imagery/illustration/texture/ambient-media and the card-avoidance rules
voice-and-tone.ts OSHUN_VOICE_TRAITS, OSHUN_PROHIBITED_COPY, OSHUN_VOICE_DO_DONT_PAIRS, OSHUN_ACCESSIBILITY_TONE_POLICIES The voice traits and prohibited-copy patterns, with do/don't pairs
ai-disclosure-copy.ts OSHUN_DISCLOSURE_COPY, OSHUN_DISCLOSURE_SURFACE_RULES, OSHUN_AI_DISCLOSURE_PREFERRED_TERMS, OSHUN_AI_DISCLOSURE_BANNED_TERMS Canonical AI-disclosure copy and the terms you may/may not use
failure-copy.ts OSHUN_FAILURE_TEMPLATES, OSHUN_INCIDENT_TITLES, title/body token budgets Error/outage/fallback copy with word/sentence budgets
visual-qa.ts OSHUN_QA_VIEWPORTS, OSHUN_VISUAL_QA_CLAIMS (playwright-visual-qa-v1) The Playwright visual-QA checklist and viewport matrix
completion-audit.ts OSHUN_29X_COMPLETION_REQUIREMENTS The 29.X design-system requirement audit

Why a catalog instead of "just look at the code"#

component-catalog.ts exists, per its own header, so "completion can be verified without manually reading barrels." OSHUN_REQUIRED_COMPONENT_REQUIREMENTS enumerates the 22 required reusable components from the feature list — domain-switcher, continuity-card, evidence-card, evidence-sidebar, claim-item, source-item, passage-item, notebook, collection, assistant-disclosure, memory-state, provenance-badge, admin-queue, admin-filter, incident-severity, sla-timer, review-decision, policy-diff, avatar, voice-pack, rights-summary, license-summary — grouped into navigation, continuity, evidence, library, assistant, admin, policy, embodiment, and rights. Each OshunComponentCatalogEntry records its canonicalExport, implementationPath, testPath, whether it appears in the customerShell and/or adminShell, and the requiredA11yChecks (from accessible-name, keyboard, focus-visible, semantic-state, screen-reader-copy). A coverage function can then assert that every requirement is met — turning "we have a component library" into a machine-checked claim.

Accessibility, copy, and ergonomics as first-class rules#

The OSHUN_EXPERIENCE_QUALITY_RULES object fixes the non-negotiables:

  • Accessibility: visible focus, reduced motion parity, high-contrast tokens, screen-reader labels. The high-contrast token requirement is satisfied by the highContrastLight/highContrastDark themes; reduced-motion parity is expressed through oshunMotionTokens.
  • Disclosure: body-copy disclosure, provenance link, confidence band, source count — the AI-honesty quartet, backed by oshunDisclosureUiBehavior and the OSHUN_DISCLOSURE_COPY/OSHUN_AI_DISCLOSURE_BANNED_TERMS rules.
  • Layout: 8px component radius ceiling, no nested cards, stable control dimensions, Tara-first home ordering — the card-avoidance rule is enforced by surface-language.ts, the ordering by assertSurfaceUsesTaraLanguage().
  • Mobile: one-handed primary actions, large tap targets, offline read fallback, handoff continuity — the thumb-zone model and one-handed surface contracts in ergonomics.ts make this checkable per surface.

The copy rules deserve emphasis because they are the part most easily faked. AI disclosure copy is canonical (OSHUN_DISCLOSURE_COPY) with explicit OSHUN_AI_DISCLOSURE_PREFERRED_TERMS and OSHUN_AI_DISCLOSURE_BANNED_TERMS, so a surface cannot, for example, call a generated answer "verified" when it is "AI-assisted." Failure/outage copy is bounded by token budgets (OSHUN_FAILURE_TITLE_TOKEN_BUDGET = { minWords: 3, maxWords: 6 }, OSHUN_FAILURE_BODY_TOKEN_BUDGET = { minSentences: 1, maxSentences: 2 }) so error states stay short, calm, and non-shaming under stress — the moment users most need plain language.

Localized strings and formatting (@oshun/i18n)#

Localization is part of the design system, not an afterthought, because text length and direction reshape layout. libs/oshun/i18n/src/index.ts is the canonical catalog. (The web app layers next-intl on top — apps/oshun/web/src/i18n/config.ts defines locales = OSHUN_LAUNCH_LANGUAGE_PREFERENCES and derives rtlLocales from RTL_LOCALES — but the shared catalog underneath is what guarantees coverage and fallback.) For the full localization story see Taxonomy, Localization, and Versioning; the design-system-relevant facts are:

  • Eight launch locales. OSHUN_LAUNCH_LOCALES = ['en-US','es-US','fr-FR', 'de-DE','ar','he','ja-JP','pt-BR'], with OSHUN_DEFAULT_LAUNCH_LOCALE = 'en-US' and RTL_LOCALES = {ar, he}. localeDirection() returns 'rtl' for Arabic and Hebrew so shells flip rather than break.
  • Text-expansion budgets drive layout QA. LOCALE_EXPANSION_BUDGET records, per locale, how much longer than the en-US baseline a string may run while still fitting the same shell: de-DE 1.4 (the widest), fr-FR 1.3, pt-BR 1.3, es-US 1.25, ar 1.2, he 1.15, and ja-JP 0.7 (the only one that contracts). Layout QA verifies a de-DE label at 1.4x does not truncate or break a grid column.
  • A complete working catalog, not just "externalized strings." CUSTOMER_MESSAGES is a frozen map of customer-facing keys — covering shell navigation, AI disclosures, memory state, evidence/provenance, offline states, errors, status, auth, and privacy — fully translated across all eight locales. The catalog is keyed message-first then locale-second precisely so per-key audits ("which locales does this key cover?") are trivial.
  • Translation with a defined fallback chain. translate(key, locale, options) resolves through resolveFallbackChain() — requested locale → language-only locale → en-US (so es-US tries es-US, then es, then en-US). It returns a TranslationResult of { value, resolvedLocale, fallbackApplied }, and emits a TranslationFallbackEvent when a fallback fired, so gaps are observable in telemetry rather than silent.
  • Critical messages are flagged. isCriticalMessageKey() marks any key under the prefixes assistant.disclosure., evidence., auth.minimum_version_required, or privacy. as critical — a fallback on a legally or safety-relevant string (an AI disclosure, a provenance label, a consent notice) is treated differently from a fallback on a nav label.
  • Gap detection for launch readiness. findFallbackGaps() walks every key against every locale and returns any <key, locale> pair that resolves via fallback rather than a direct hit — a non-empty result is a translation gap to close before launch.
  • Locale-aware formatting. formatForLocale() produces date, time, date-time, timezone, currency, number, region, and relative-time strings using the platform Intl.DateTimeFormat, Intl.NumberFormat, Intl.RelativeTimeFormat, and Intl.DisplayNames with explicit options. All eight launch locales currently use the Gregorian calendar (LOCALE_CALENDAR); the Japanese imperial calendar is reserved for specific opted-in cultural surfaces.

Visual QA and design review#

Visual QA is encoded, not improvised. visual-qa.ts defines the viewport matrix OSHUN_QA_VIEWPORTS and a list of OSHUN_VISUAL_QA_CLAIMS (playwright-visual-qa-v1) that the design-review and Playwright-backed checklist runs against — covering shell, domain, admin, and the mobile/desktop/laptop/tablet/narrow-mobile states called for in the feature list. Those claims feed the broader accessibility and Lighthouse CI coverage tracked in Analytics, Observability, Testing, and Security, which is also where the web performance budgets (apps/oshun/web/lighthouse-budget.json) and the per-journey automation matrix live.

Honesty note#

The token, component, i18n, and design-language modules described above are real, sizeable, tested code in libs/oshun/*. What this page does not assert is that a full live Lighthouse, axe, or Playwright sweep currently passes on every route — the budget files and CI-coverage manifests exist, but a green run is a property of CI at a given commit, not of these source files. Where a claim is a process gate rather than shipped code, the analytics-and-testing.md page says so explicitly.