
Dashboard Patterns
- 1 installs
- 1 repo stars
- Updated June 17, 2026
- cleanexpo/unite-hub
Helps with ai & agent building tasks.
About
dashboard-patterns is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- dashboard-patterns
- AI & Agent Building
- AI-coding skill
Dashboard Patterns by the numbers
- 1 all-time installs (skills.sh)
- Ranked #14,102 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Jul 28, 2026 (Skillselion catalog sync)
npx skills add https://github.com/cleanexpo/unite-hub --skill dashboard-patternsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 1 |
| Last updated | June 17, 2026 |
| Repository | cleanexpo/unite-hub ↗ |
What it does
Helps with ai & agent building tasks.
Files
Dashboard Patterns - Real-Time Data Visualisation
Codifies the project's existing dashboard architecture: the Status Command Centre component library, backend analytics APIs, and the Scientific Luxury design rules that govern every data surface. Enforces timeline layout, spectral colours, physics-based animations, and Australian locale formatting.
Description
Codifies real-time dashboard patterns for NodeJS-Starter-V1 including the Status Command Centre component library, timeline/orbital layouts, Supabase Realtime integration, spectral colour mapping, and Scientific Luxury design enforcement for all data visualisation surfaces.
---
When to Apply
Positive Triggers
- Building new dashboard pages or metric displays
- Adding real-time data visualisation components
- Integrating Supabase Realtime for live updates
- Creating loading skeletons or empty states for dashboards
- Composing MetricTile, DataStrip, or ProgressOrb components
- Reviewing dashboard layouts for Scientific Luxury compliance
- User mentions: "dashboard", "metrics display", "real-time", "monitoring UI", "command centre"
Negative Triggers
- Collecting or storing metrics data (use
metrics-collectorinstead) - Designing email templates (use
email-templateinstead) - Adding log statements (use
structured-logginginstead) - Implementing non-dashboard UI components (use
scientific-luxuryinstead)
Core Directives
The Three Laws of Dashboards
1. Timeline, never grid: No grid-cols-2/grid-cols-4 layouts. Use vertical timelines, horizontal data strips, and orbital arrangements. 2. Spectral, never static: Every status maps to a spectral colour with breathing animation. No grey placeholder states. 3. Real-time, never stale: Live data via Supabase Realtime or 30-second polling. Always show connection status.
---
Existing Project Infrastructure
Component Library
Location: apps/web/components/status-command-centre/
| Category | Components |
|---|---|
| Main | StatusCommandCentre (full/compact/minimal variants) |
| Data Display | DataStrip (horizontal metrics), MetricTile (stat tile with trends) |
| Visualisation | ProgressOrb, ProgressRing, StatusPulse, StatusBadge |
| Activity | AgentNode, AgentActivityCard, ActivityTimeline, AgentThinkingIndicator |
| Utility | NotificationStream, ElapsedTimer |
| Hooks | useElapsedTime, useCountdown, useStatusTransitions, useStatusColourTransition |
| Utils | formatElapsedAU, formatTimestampAU, formatDateAU, getAustralianTimezone |
Dashboard Pages
| Page | Location | Data Source |
|---|---|---|
| Agent Dashboard | apps/web/app/(dashboard)/agents/page.tsx | /api/agents/stats, /api/agents/list |
| Analytics Dashboard | apps/web/app/dashboard-analytics/page.tsx | /api/analytics/metrics/overview |
| Status Command Centre | Embedded component | Supabase Realtime (agent_runs table) |
Backend APIs
| Route | Location | Returns |
|---|---|---|
/analytics/metrics/overview | apps/backend/src/api/routes/analytics.py | Runs, success rate, cost, tokens |
/analytics/metrics/agents | Same file | Per-agent performance breakdown |
/analytics/metrics/costs | Same file | Cost by model, token breakdown |
/api/agents/stats | apps/backend/src/api/routes/agent_dashboard.py | Aggregate agent statistics |
/api/agents/{id}/health | Same file | AgentHealthReport model |
/api/agents/performance/trends | Same file | Time-series trend data |
---
Layout Patterns
BANNED: Card Grid
// REJECTED — violates Scientific Luxury and Timeline law
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
<Card>...</Card>
<Card>...</Card>
</div>REQUIRED: Timeline Layout
The StatusCommandCentre implements a vertical timeline spine with agent nodes:
<div className="relative pl-4">
{/* Vertical Timeline Spine */}
<motion.div
initial={{ scaleY: 0 }}
animate={{ scaleY: 1 }}
transition={{ delay: 0.3, duration: 0.8, ease: [0.19, 1, 0.22, 1] }}
className="absolute top-0 bottom-0 left-8 w-px origin-top
bg-gradient-to-b from-white/10 via-white/5 to-transparent"
/>
{/* Agent Nodes along the spine */}
<div className="space-y-8">
{runs.map((run, index) => (
<AgentNode key={run.id} run={run} index={index} />
))}
</div>
</div>REQUIRED: Horizontal Data Strip
Replace metric grids with DataStrip — inline horizontal layout with spectral-coloured values:
<DataStrip
metrics={[
{ label: 'Total', value: runs.length },
{ label: 'Active', value: activeRuns.length, variant: 'info' },
{ label: 'Completed', value: completedRuns.length, variant: 'success' },
{ label: 'Failed', value: failedRuns.length, variant: 'error' },
]}
/>DataStrip uses JetBrains Mono for values, text-[10px] tracking-widest uppercase for labels, pipe separators between metrics, and spectral glow on non-zero highlighted values.
---
Spectral Colour Mapping
Every AgentRunStatus maps to a spectral colour defined in constants.ts:
| Status | Colour | HSL | Animation |
|---|---|---|---|
pending | Slate | hsl(220 14% 46%) | Pulse (idle) |
in_progress | Blue | hsl(217 91% 60%) | Spin (active) |
awaiting_verification | Amber | hsl(38 92% 50%) | Pulse (active) |
verification_in_progress | Amber | hsl(38 92% 50%) | Spin (active) |
verification_passed | Green | hsl(142 76% 36%) | None (idle) |
verification_failed | Red | hsl(0 84% 60%) | Pulse (urgent) |
completed | Emerald | #00FF88 | None (idle) |
failed | Red | #FF4444 | Pulse (urgent) |
blocked | Slate | Muted | None (idle) |
escalated_to_human | Magenta | #FF00FF | Pulse (urgent) |
Access via getStatusConfig(status) from constants.ts. Each config includes colour (primary, glow, background), icon, animation, and intensity.
DataStrip variants use simplified spectral colours: info=#00F5FF, success=#00FF88, warning=#FFB800, error=#FF4444.
---
Animation Patterns
All animations use Framer Motion. CSS transitions are BANNED.
Staggered Entry
Components animate in sequence with delay offsets:
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.1 * index, ease: [0.19, 1, 0.22, 1] }}
>Breathing Orbs
Status indicators use breathing animation for active states:
<motion.span
className="h-1.5 w-1.5 rounded-full"
style={{ backgroundColor: config.colour.primary }}
animate={{ opacity: [1, 0.4, 1], scale: [1, 1.2, 1] }}
transition={{ duration: 2, repeat: Infinity, ease: 'easeInOut' }}
/>Ambient Glow
Active agents trigger a radial gradient background glow:
{activeRuns.length > 0 && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 0.1 }}
className="pointer-events-none absolute inset-0"
style={{ background: 'radial-gradient(ellipse at 20% 10%, hsl(217 91% 60% / 0.15) 0%, transparent 50%)' }}
/>
)}Status Transitions
Use useStatusTransitions hook to detect state changes and apply transition animations (success ripple, error shake).
---
Data Fetching Patterns
Server Components (Initial Load)
Use Next.js Server Components for initial data fetch with cache: 'no-store':
async function fetchAgentStats() {
const backendUrl = process.env.BACKEND_URL || 'http://localhost:8000';
const res = await fetch(`${backendUrl}/api/agents/stats`, { cache: 'no-store' });
if (!res.ok) return FALLBACK_STATS;
return res.json();
}Always provide fallback data so the page renders even when the backend is unavailable.
Polling (Analytics Dashboard)
For non-realtime pages, poll at 30-second intervals:
useEffect(() => {
fetchMetrics();
const interval = setInterval(fetchMetrics, 30_000);
return () => clearInterval(interval);
}, []);Supabase Realtime (Command Centre)
For the Status Command Centre, subscribe to agent_runs table changes:
const channel = supabase
.channel('agent-runs')
.on('postgres_changes', { event: '*', schema: 'public', table: 'agent_runs' },
(payload: RealtimePayload) => {
if (payload.eventType === 'INSERT') addRun(payload.new);
if (payload.eventType === 'UPDATE') updateRun(payload.new);
})
.subscribe();Types RealtimeEvent, RealtimePayload, and ConnectionStatus are defined in types.ts.
Connection Status
Always display connection state using the ConnectionIndicator component:
- Connected (Emerald breathing dot + "Live" label)
- Reconnecting (Amber dot + "Reconnecting" label)
- Disconnected (Red dot + "Offline" label)
---
Loading & Empty States
Loading Skeleton
Every dashboard page must show a skeleton that matches the final layout structure:
function LoadingSkeleton() {
return (
<div className="space-y-8">
<motion.div
className="h-10 w-64 rounded-sm bg-white/5"
animate={{ opacity: [0.5, 1, 0.5] }}
transition={{ duration: 1.5, repeat: Infinity }}
/>
{/* More skeleton elements matching the real layout */}
</div>
);
}Rules: Use bg-white/5 for skeleton blocks, rounded-sm only, breathing opacity animation, staggered delays per element.
Empty State
When no data is available, show a centred empty state with a breathing orb:
<div className="flex flex-col items-center justify-center py-20">
<motion.div
className="h-3 w-3 rounded-full bg-white/20"
animate={{ scale: [1, 1.5, 1], opacity: [0.5, 1, 0.5] }}
transition={{ duration: 2, repeat: Infinity, ease: 'easeInOut' }}
/>
<h3 className="text-xl font-light text-white">No Active Agents</h3>
<p className="font-mono text-xs text-white/40">Description text.</p>
</div>---
Component Composition
New Dashboard Page Template
Every dashboard page follows this structure:
// 1. Server Component wrapper (data fetch)
export default async function DashboardPage() {
const data = await fetchData();
return (
<div className="relative min-h-screen bg-[#050505]">
{/* Header */}
<header className="border-b border-white/[0.06] px-8 py-6">
<p className="text-[10px] tracking-[0.3em] text-white/30 uppercase">Category Label</p>
<h1 className="text-4xl font-extralight tracking-tight text-white">Page Title</h1>
<DataStrip metrics={[...]} />
</header>
{/* Content — timeline or orbital, never grid */}
<Suspense fallback={<LoadingSkeleton />}>
<DashboardContent data={data} />
</Suspense>
{/* Footer */}
<footer className="px-8 py-4">
<p className="font-mono text-[10px] text-white/20">
{new Date().toLocaleDateString('en-AU')}
</p>
</footer>
</div>
);
}When to Use Each Component
| Need | Component | Import From |
|---|---|---|
| Inline metrics row | DataStrip | status-command-centre |
| Single stat with trend | MetricTile | status-command-centre |
| Agent execution status | AgentNode | status-command-centre |
| Circular progress | ProgressOrb or ProgressRing | status-command-centre |
| Status dot | StatusPulse | status-command-centre |
| Status label | StatusBadge | status-command-centre |
| Step timeline | ActivityTimeline | status-command-centre |
| Notification sidebar | NotificationStream | status-command-centre |
| Elapsed time counter | ElapsedTimer | status-command-centre |
---
Anti-Patterns
| Anti-Pattern | Why It Fails | Correct Approach |
|---|---|---|
grid-cols-2 / grid-cols-4 metric cards | Violates Scientific Luxury layout rules | DataStrip or timeline layout |
Standard <Card> with rounded-lg | Wrong corners, wrong aesthetic | rounded-sm border-[0.5px] border-white/[0.06] |
CSS transition: all 0.3s linear | Banned by Bezier (Council of Logic) | Framer Motion with physics-based easing |
| White/light background dashboards | Violates OLED black requirement | bg-[#050505] always |
| No loading skeleton | Layout shift on data load | Skeleton matching final layout structure |
| No connection indicator | Users cannot tell if data is live | ConnectionIndicator in every realtime page |
| Hardcoded status colours | Drift from spectral palette | getStatusConfig(status).colour |
setInterval without cleanup | Memory leak on unmount | useEffect with clearInterval in cleanup |
---
Checklist for New Dashboard Pages
Layout
- [ ] OLED black background (
bg-[#050505]) - [ ] Timeline or orbital layout (no card grids)
- [ ]
DataStripfor summary metrics (not metric grid) - [ ] Single pixel borders (
border-[0.5px] border-white/[0.06]) - [ ]
rounded-smonly (norounded-lg,rounded-xl) - [ ] JetBrains Mono for data values
Data
- [ ] Server Component for initial fetch with fallback data
- [ ] Polling interval (30s) or Supabase Realtime subscription
- [ ] Connection status indicator shown
- [ ] Loading skeleton matching final layout
- [ ] Empty state with breathing orb
Animation
- [ ] Framer Motion for all transitions (no CSS transitions)
- [ ] Staggered entry for list items
- [ ] Breathing animation for active status indicators
- [ ] Ambient glow when agents are active
Integration
- [ ] Uses
metrics-collectorMetricsRegistryfor data source - [ ] Spectral colours from
STATUS_CONFIGconstants - [ ] Australian locale formatting (
formatDateAU,formatTimestampAU) - [ ] Types imported from
status-command-centre/types.ts
---
Response Format
[AGENT_ACTIVATED]: Dashboard Patterns
[PHASE]: {Design | Implementation | Review}
[STATUS]: {in_progress | complete}
{dashboard analysis or implementation guidance}
[NEXT_ACTION]: {what to do next}Integration Points
Scientific Luxury
- OLED black background, spectral colours, single-pixel borders, physics-based animations
- All dashboard components enforce the design system automatically via
constants.ts
Metrics Collector
MetricsRegistryprovides the data layer (counters, gauges, histograms)- Time-series aggregation powers trend charts
- Summary endpoint feeds
DataStripandMetricTilecomponents
State Machine
AgentRunStatus(10 states) maps directly toSTATUS_CONFIGcolour/animation entriesuseStatusTransitionshook handles state change animations
Structured Logging
- Dashboard pages log
dashboard_loaded,dashboard_errorevents - Connection status changes logged for debugging
Cron Scheduler
- Cron job metrics displayed via
DataStriporMetricTile - Daily report data powers the analytics dashboard trends
Australian Localisation (en-AU)
- Date Format: DD/MM/YYYY via
formatDateAU()utility - Time: H:MM am/pm AEST/AEDT via
formatTimeAU()andgetAustralianTimezone() - Currency: AUD ($) —
total_cost_usdconverted to AUD for display - Spelling: colour, behaviour, analyse, optimise, centre
- Footer: Australian date format in dashboard footers