Prox OS Docs
Design

Component Layering and UI Encapsulation

Define what belongs in packages/os-ui, what belongs in apps/shell orchestration, and how headless primitives should be sealed. Visual tokens are documented in [

Purpose

Define what belongs in packages/os-ui, what belongs in apps/shell orchestration, and how headless primitives should be sealed. Visual tokens are documented in tokens.md; shell chrome rules in os-shell-design-language.md.

Current Status

@prox-os/os-ui exports shell-oriented primitives and layout pieces (see packages/os-ui/src/index.ts). Radix/Ariakit-style dependencies, if present, should remain implementation details inside os-ui — not re-exported as the public app API.

Layer Model

┌─────────────────────────────────────────────┐
│  apps/os-shell, packages/os-apps            │  Product logic, registry, Zustand, Query
├─────────────────────────────────────────────┤
│  packages/os-ui                             │  Presentational shell components
├─────────────────────────────────────────────┤
│  @prox-os/design-tokens                     │  --os-* CSS, Tailwind bridge
├─────────────────────────────────────────────┤
│  Headless primitives (Radix, etc.)          │  Only inside os-ui when needed
└─────────────────────────────────────────────┘

What Belongs in os-ui

  • Pure presentational components: Panel, Surface, WindowFrame, CommandSurface, Dock, ShellBar, …
  • Accessible wrappers and keyboard/focus behavior for those primitives.
  • Components that read CSS variables (var(--os-color-*)) and density/theme attributes on ancestors.
  • Shared hooks that are UI-only (e.g. dialog escape handling) without business data.

Exports today (observation): packages/os-ui/src/index.ts — primitives under primitives/, shell under shell/.

What Does Not Belong in os-ui

  • App registry, manifest resolution, or route group logic.
  • Zustand stores or window manager actions.
  • TanStack Query hooks or API clients.
  • App i18n bundles (apps/os-shell/src/i18n/** is shell-owned).
  • Per-app business tables, forms tied to domain entities, or App Store catalog data.

Enforced by dependency-cruiser rules (package-graph.md).

Shell vs App Components

LocationExamplesMay use
packages/os-uiWindowControls, CommandSurfacetokens, local UI state
apps/os-shell/src/shell/**DesktopScene, GlobalShortcuts, MissionControlOverlayos-ui, Zustand, router
packages/os-appsProjectsApp, AppStoreAppos-ui, app-contract runtime props
apps/os-shell/src/apps/**DisplayOptionsApp, Architecture local modulecontract adapters, os-ui

Apps should compose os-ui + tokens; they should not fork window chrome.

Headless Primitive Policy

Decision: Business code imports @prox-os/os-ui, not @radix-ui/* (or similar) directly.

Why:

  • Centralizes accessibility and focus traps.
  • Allows primitive swaps without rewriting every app.
  • Prevents visual drift (spacing, radius, motion).

Exception process: Document in PR + add wrapper in os-ui first.

Storybook / UI Workshop

apps/ui-workshop is the visual acceptance surface for Próx OS: it loads @prox-os/design-tokens and @prox-os/os-ui/tokens.css plus Tailwind (same bridge as the shell). Stories live under apps/ui-workshop/src/stories/** and must stay decoupled from shell Zustand, registry, and routing.

Foundation components documented in Storybook (round 1): WindowFrame, Dock, ShellBar, AppTile, EmptyState (plus existing StatusPill variants). Shell code in apps/os-shell keeps state ownership (window manager, active app, workspaces); only presentational pieces belong in os-ui.

Use the workshop when adding primitives or changing chrome density — not as a second design system.

Anti-Patterns

  1. Importing shell Zustand from os-ui.
  2. Passing entire appRegistry into a primitive for convenience.
  3. Hard-coded hex in os-ui instead of --os-* variables.
  4. Duplicating WindowFrame inside an app to “customize” one screen — extend via tokens or shell-approved slots.
  • packages/os-ui/src/index.ts
  • packages/os-ui/src/shell/*
  • apps/os-shell/src/shell/DesktopScene.tsx (orchestration)
  • .dependency-cruiser.js

On this page