20 KiB
OpenClaw Control Center — Command Hub
Senior Product Designer Specification (7-Point)
Version: 1.0
Date: 2026-04-21
Designer: Sketch (UI/UX Agent)
Status: Implementation-Ready
Design System: Material Design 3 (https://m3.material.io/)
Aesthetic: Tactical Dark Mode
1. Objective
Design the Command Hub — the primary entry point and nerve centre for the OpenClaw Control Center. This screen enables operators to monitor all active agents at a glance, assess fleet health in under 3 seconds, and jump directly into any agent session without friction.
The design must serve two primary mental models:
- Triage Mode — scan for errors, stalls, and anomalies fast
- Navigation Mode — get into a specific agent session instantly
This is a utility-first, operator-grade interface. It is not a marketing page. Every pixel earns its place.
2. Screen Inventory
| Screen | Description | Trigger |
|---|---|---|
| Command Hub | Fleet Status grid + global nav | App launch / Home |
| Agent Session View | Full session detail for one agent | Quick-Jump tap |
| Session Log | Full scrollable log history | Long-press agent card or log icon |
| Task Breakdown | Subtask waterfall for active task | Tap active task chip on card |
| Settings / Config | Global config, theme, agents list | Nav Rail → Settings |
| Notifications Panel | Alert history and system events | Bell icon / swipe |
3. Layout Specification
3.1 Kiosk Layout (≥ 1024px — Fixed Display / Raspberry Pi HDMI)
┌─────────────────────────────────────────────────────────────────┐
│ NAV RAIL (72px) │ MAIN CONTENT AREA │
│ │ │
│ [☰] OpenClaw │ ┌─ HEADER BAR ─────────────────────────┐ │
│ │ │ "Command Hub" [🔔 3] [●Live] [⚙] │ │
│ [⚡] Command Hub │ └──────────────────────────────────────┘ │
│ [📋] Projects │ │
│ [🗂] Sessions │ ┌─ FLEET STATUS ────────────────────────┐ │
│ [📊] Logs │ │ FILTER: [All ▾] [Active] [Error] │ │
│ ───────── │ │ │ │
│ [⚙] Settings │ │ ┌──────────┐ ┌──────────┐ ┌──────┐ │ │
│ [👤] Profile │ │ │ AGENT │ │ AGENT │ │AGENT │ │ │
│ │ │ │ CARD │ │ CARD │ │ CARD │ │ │
│ │ │ └──────────┘ └──────────┘ └──────┘ │ │
│ │ │ ┌──────────┐ ┌──────────┐ ... │ │
│ │ │ │ AGENT │ │ AGENT │ │ │
│ │ │ │ CARD │ │ CARD │ │ │
│ │ │ └──────────┘ └──────────┘ │ │
│ │ └────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
Nav Rail: 72px collapsed, 256px expanded. M3 NavigationRail component. Always visible on kiosk.
Main Content: 3-column agent card grid (CSS Grid, repeat(auto-fill, minmax(340px, 1fr))). 24px gutter.
Header Bar: 64px tall. App title + live indicator + notification bell + settings.
3.2 Mobile Layout (< 768px — Phone / Tablet)
┌───────────────────────────────┐
│ ┌─ HEADER ──────────────────┐│
│ │ ≡ Command Hub 🔔 ⚙ ││
│ └────────────────────────────│
│ │
│ [All ▾] [Active 4] [Error 1] │
│ │
│ ┌──────────────────────────┐ │
│ │ AGENT CARD (full width) │ │
│ └──────────────────────────┘ │
│ ┌──────────────────────────┐ │
│ │ AGENT CARD (full width) │ │
│ └──────────────────────────┘ │
│ ┌──────────────────────────┐ │
│ │ AGENT CARD (full width) │ │
│ └──────────────────────────┘ │
│ │
│ ───────────────────────────── │
│ [⚡Hub] [📋Projects] [📊Logs] │
│ BOTTOM NAV BAR │
└───────────────────────────────┘
Bottom Navigation: M3 NavigationBar. 3–5 destinations. Active destination uses M3 indicator pill.
Cards: Single-column, full-width. Scrollable list. 16px horizontal padding.
3.3 Agent Card Component (Core Unit)
┌─────────────────────────────────────────────────────┐
│ ● ACTIVE [otto] [→ Jump] │
│ ─────────────────────────────────────────────────── │
│ 🤖 Otto │
│ Orchestrator Agent │
│ │
│ TASK: Reviewing PR #42 — extrudex-ui │
│ ████████████░░░░░░ 62% — 04m 12s elapsed │
│ │
│ SESSION: agent:otto:telegram:direct:8787... │
│ CHANNEL: Telegram [●] Last msg: 2m ago │
└─────────────────────────────────────────────────────┘
Card anatomy:
- Status Badge (top-left): Color pill — Active / Idle / Thinking / Error
- Agent Tag (top-center): Short ID chip
- Quick-Jump CTA (top-right):
→ Jumpicon button — M3FilledTonalIconButton - Avatar + Name + Role (mid-section): M3 List tile pattern
- Active Task Row: Task name + linear progress indicator
- Session Footer: Session key truncated + channel + last activity timestamp
Card states:
- Default — surface container background, subtle border
- Active — cyan left-border accent (4px), slightly elevated
+2dp - Error — red border, pulsing status dot
- Thinking — purple status + animated shimmer on task row
- Idle — muted, desaturated, lower elevation
- Hover/Focus — M3 state layer overlay (8% primary)
3.4 Quick-Jump Mechanism
On tap of → Jump button on any agent card:
-
Modal Bottom Sheet (mobile) — M3
ModalBottomSheetslides up with:- Agent name + status
- Last 3 messages (truncated)
- [Open Full Session] FAB
- [View Logs] secondary action
-
Side Drawer Panel (kiosk/desktop) — M3
NavigationDrawer(modal variant) slides in from right (480px wide) with:- Agent name + session context
- Live log tail (last 20 lines, auto-scroll)
- [Open Full Session] primary button
- [Pin to Dashboard] secondary action
Keyboard / touch shortcut: Long-press card = opens Session Log directly (bypasses Quick-Jump drawer).
3.5 Global Navigation Structure
| Destination | Icon | Badge |
|---|---|---|
| Command Hub | ⚡ Flash | None |
| Projects | 📋 Clipboard | Active count |
| Sessions | 🗂 Stack | Unread count |
| Logs | 📊 Chart | Error count |
| Settings | ⚙ Gear | — |
Rail behavior: Collapsed by default on kiosk. Tap hamburger ☰ to expand with labels.
Bottom nav (mobile): Always shows labels. Max 5 destinations. Overflow → menu.
4. UX Rationale
Why Navigation Rail (Desktop) + Bottom Nav (Mobile)?
M3's adaptive navigation pattern — NavigationRail is the correct M3 component for persistent navigation on expanded screens. It keeps the full content width for the fleet grid. On mobile, NavigationBar (bottom) is ergonomically correct for thumb reach. The two layouts share identical navigation destinations but adapt the component.
Why Card Grid, Not Table?
- Cards are touch-friendly (minimum 56px tap area per cell)
- Cards support rich visual status — tables flatten the hierarchy
- Cards allow progressive disclosure (collapsed vs expanded state)
- Tables are for data comparison; cards are for status triage
Why Quick-Jump Drawer, Not Page Navigation?
Operators often want to peek at an agent without losing the fleet overview. A drawer preserves context — the fleet grid remains visible behind it. Full navigation to the agent session view is a secondary action requiring intentional tap.
Why Left-Border Accent on Active Cards?
It's a scannable, pre-attentive visual cue. Eyes detect vertical color stripes faster than color fills. Lifted from terminal/IDE design patterns (like VS Code activity indicators). Consistent with Tactical Dark Mode aesthetics.
Information Hierarchy on Card
Status → Identity → Current Task → Session Context
This ordering maps to the triage mental model: "Is it ok? Who is it? What's it doing? Where is it?"
5. Visual Direction
5.1 Color Palette (M3 Dynamic Color — Custom Dark Scheme)
| Role | Token | Hex | Usage |
|---|---|---|---|
| Background | md.sys.color.background |
#0D0F12 |
App background |
| Surface | md.sys.color.surface |
#13161A |
Card background |
| Surface Container | md.sys.color.surface-container |
#1C2027 |
Elevated cards |
| Surface Container High | md.sys.color.surface-container-high |
#252B33 |
Header, Nav Rail |
| On Surface | md.sys.color.on-surface |
#E2E8F0 |
Primary text |
| On Surface Variant | md.sys.color.on-surface-variant |
#8A9BB0 |
Secondary text |
| Outline | md.sys.color.outline |
#2D3748 |
Card borders |
| Primary | md.sys.color.primary |
#38BDF8 |
Active state, CTAs (Electric Blue) |
| On Primary | md.sys.color.on-primary |
#0C1825 |
Text on primary |
| Secondary | md.sys.color.secondary |
#64748B |
Nav inactive |
| Tertiary | md.sys.color.tertiary |
#A78BFA |
Thinking state (Amethyst) |
Status Colors (Semantic — outside M3 tonal system):
| Status | Color | Hex | Dot Animation |
|---|---|---|---|
| Active | Electric Blue | #38BDF8 |
Steady pulse (2s) |
| Idle | Muted Teal | #2DD4BF |
Static |
| Thinking | Amethyst | #A78BFA |
Slow pulse (3s) |
| Error | Vivid Red | #F87171 |
Fast pulse (0.8s) |
5.2 Typography
M3 Type Scale using Inter (primary) with Roboto Mono for session IDs and log output.
| Role | M3 Token | Size | Weight | Usage |
|---|---|---|---|---|
| Display Small | displaySmall |
36sp | 400 | Screen title |
| Headline Medium | headlineMedium |
28sp | 400 | Agent name |
| Title Large | titleLarge |
22sp | 500 | Section headers |
| Title Medium | titleMedium |
16sp | 500 | Card title |
| Body Medium | bodyMedium |
14sp | 400 | Task description |
| Label Large | labelLarge |
14sp | 500 | Buttons, badges |
| Label Small | labelSmall |
11sp | 500 | Status chips, timestamps |
| Mono Body | — | 13sp | 400 | Session IDs, log text |
5.3 Elevation & Surfaces
Using M3's tonal surface elevation (not drop shadows):
| Level | Overlay | Usage |
|---|---|---|
| Level 0 | 0% | App background |
| Level 1 | 5% | Cards (default) |
| Level 2 | 8% | Cards (active/hover) |
| Level 3 | 11% | Navigation Rail |
| Level 4 | 12% | Header / App Bar |
| Level 5 | 14% | Modal overlays |
5.4 Spacing & Grid
- Base unit: 8px
- Card padding: 20px (2.5 units)
- Card gap (grid): 16px (2 units)
- Section padding: 24px (3 units)
- Nav Rail width collapsed: 72px
- Nav Rail width expanded: 256px
- Card min-width: 320px, preferred: 360px
- Card border-radius: 16px (M3 ExtraLarge shape token)
- Status dot size: 10px
5.5 Iconography
M3 Material Symbols (Outlined weight, FILL=0, wght=400, GRAD=0, opsz=24).
Key icons:
- Agent status dot: Custom SVG animated circle
- Quick-Jump:
arrow_forwardoropen_in_new - Active:
bolt - Thinking:
psychologyorautorenew - Error:
error_outline - Idle:
pause_circle - Settings:
settings - Notifications:
notifications
6. Responsiveness
Breakpoints (M3 Adaptive Layout)
| Breakpoint | Width | Layout | Navigation | Columns |
|---|---|---|---|---|
| Compact | 0–599px | Mobile | Bottom Nav | 1 |
| Medium | 600–1023px | Tablet | Nav Rail (collapsed) | 2 |
| Expanded | ≥ 1024px | Desktop/Kiosk | Nav Rail (expandable) | 3+ |
Adaptive Behaviors
Compact (Phone):
- Cards: Full-width, stacked vertically
- Quick-Jump: Modal Bottom Sheet
- Header: Small top app bar (M3
SmallTopAppBar) - Status filter: Horizontal scroll chip group
Medium (Tablet):
- Cards: 2-column grid
- Nav Rail: Collapsed (icons only)
- Quick-Jump: Side panel (half-width drawer)
Expanded (Kiosk/Desktop):
- Cards: 3+ column auto-fill grid
- Nav Rail: Expandable with labels
- Quick-Jump: Side drawer (480px)
- Header: Medium top app bar with subtitle
Touch Targets
- All interactive elements: minimum 48×48dp (M3 spec)
- Card tap area: full card (not just button)
- Quick-Jump button: 56×56dp (touch-optimized)
- Bottom nav items: minimum 48dp height
7. Developer Handoff Notes
7.1 Technology Stack
- Frontend: Angular 17+ with Angular Material (M3 theming)
- Realtime: SignalR WebSocket hub —
AgentStatusHub - State Management: NgRx (recommended) or Angular Signals
- Styling: Angular Material theming + custom CSS custom properties for status colors
7.2 M3 Theme Configuration (Angular Material)
// _theme.scss
@use '@angular/material' as mat;
$dark-theme: mat.define-theme((
color: (
theme-type: dark,
primary: mat.$cyan-palette, // #38BDF8 family
tertiary: mat.$violet-palette, // #A78BFA family
),
typography: (
brand-family: 'Inter, sans-serif',
plain-family: 'Inter, sans-serif',
bold-weight: 600,
medium-weight: 500,
regular-weight: 400,
),
density: (
scale: 0,
),
));
// Custom CSS vars for status colors
:root {
--status-active: #38BDF8;
--status-idle: #2DD4BF;
--status-thinking: #A78BFA;
--status-error: #F87171;
--status-active-bg: rgba(56, 189, 248, 0.12);
--status-error-bg: rgba(248, 113, 113, 0.12);
}
7.3 Agent Card Component Interface
interface AgentCardData {
id: string; // e.g., "otto"
displayName: string; // e.g., "Otto"
role: string; // e.g., "Orchestrator Agent"
status: AgentStatus; // 'active' | 'idle' | 'thinking' | 'error'
currentTask?: string; // e.g., "Reviewing PR #42"
taskProgress?: number; // 0–100
taskElapsed?: string; // e.g., "04m 12s"
sessionKey: string; // full session key
channel: string; // e.g., "telegram"
lastActivity: Date;
errorMessage?: string; // populated on error state
}
type AgentStatus = 'active' | 'idle' | 'thinking' | 'error';
7.4 SignalR Integration
// agent-status.service.ts
export class AgentStatusService {
private hubConnection: HubConnection;
connect() {
this.hubConnection = new HubConnectionBuilder()
.withUrl('/hubs/agent-status')
.withAutomaticReconnect()
.build();
this.hubConnection.on('AgentStatusChanged', (update: AgentStatusUpdate) => {
this.store.dispatch(AgentActions.statusUpdated({ update }));
});
this.hubConnection.on('AgentTaskProgress', (progress: TaskProgressUpdate) => {
this.store.dispatch(AgentActions.taskProgressUpdated({ progress }));
});
}
}
7.5 Animation Specs
/* Status dot pulse animations */
@keyframes pulse-active {
0%, 100% { opacity: 1; transform: scale(1); }
50% { opacity: 0.7; transform: scale(1.15); }
}
@keyframes pulse-error {
0%, 100% { opacity: 1; }
50% { opacity: 0.4; }
}
@keyframes pulse-thinking {
0%, 100% { opacity: 0.8; }
50% { opacity: 0.4; }
}
.status-dot--active { animation: pulse-active 2s ease-in-out infinite; }
.status-dot--error { animation: pulse-error 0.8s ease-in-out infinite; }
.status-dot--thinking { animation: pulse-thinking 3s ease-in-out infinite; }
.status-dot--idle { /* static */ }
/* Quick-jump card border accent */
.agent-card--active { border-left: 4px solid var(--status-active); }
.agent-card--error { border-left: 4px solid var(--status-error); }
.agent-card--thinking { border-left: 4px solid var(--status-thinking); }
.agent-card--idle { border-left: 2px solid var(--md-sys-color-outline); }
7.6 Angular Component Structure
src/app/
command-hub/
command-hub.component.ts ← Shell, grid layout
command-hub.component.html
command-hub.component.scss
components/
agent-card/
agent-card.component.ts ← Core card unit
agent-card.component.html
agent-card.component.scss
fleet-status-filter/
fleet-status-filter.component.ts
quick-jump-drawer/
quick-jump-drawer.component.ts ← Side drawer (desktop)
quick-jump-sheet/
quick-jump-sheet.component.ts ← Bottom sheet (mobile)
services/
agent-status.service.ts
store/
agent.actions.ts
agent.reducer.ts
agent.selectors.ts
agent.effects.ts
7.7 Accessibility
- All status indicators must have text alternatives (
aria-label="Status: Active") - Cards are
role="article"witharia-labelledbypointing to agent name - Color is never the ONLY differentiator — icons accompany all status colors
- Focus ring: M3 focus indicator (3dp ring,
md.sys.color.secondary) - Reduced motion: all pulse animations respect
prefers-reduced-motion: reduce - Live region for status changes:
aria-live="polite"on status badge
7.8 Performance Notes
- Agent cards use
@defer(Angular 17) for lazy rendering below the fold - SignalR updates trigger only targeted card updates via NgRx selectors (no full re-render)
- Status dot animations use
will-change: transform, opacityfor GPU compositing - Limit fleet grid to visible viewport; virtual scroll for > 20 agents (
@angular/cdk/scrolling)
Appendix A: Status Color Reference Card
● #38BDF8 ACTIVE — Agent currently processing a task
● #2DD4BF IDLE — Agent online, no active task
● #A78BFA THINKING — Agent processing/reasoning (LLM call in flight)
● #F87171 ERROR — Agent encountered an unhandled error
○ #64748B OFFLINE — Agent unreachable / session terminated
Appendix B: Quick-Jump UX Flow
User taps [→ Jump] on Agent Card
│
├─ Desktop/Kiosk ──► Right side drawer slides in (480px)
│ Shows: live log tail, last msgs, [Open Full Session]
│
└─ Mobile ──────────► Modal Bottom Sheet rises
Shows: agent name, 3 recent msgs, [Open Full Session]
User taps [Open Full Session]
│
└─ Router navigate to /sessions/:agentId
Full page Agent Session View
Spec v1.0 — Ready for implementation. Questions → Sketch (UI/UX Agent)