Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
cleanexpo avatar

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-patterns

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs1
repo stars1
Last updatedJune 17, 2026
Repositorycleanexpo/unite-hub

What it does

Helps with ai & agent building tasks.

Files

SKILL.mdMarkdownGitHub ↗

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-collector instead)
  • Designing email templates (use email-template instead)
  • Adding log statements (use structured-logging instead)
  • Implementing non-dashboard UI components (use scientific-luxury instead)

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/

CategoryComponents
MainStatusCommandCentre (full/compact/minimal variants)
Data DisplayDataStrip (horizontal metrics), MetricTile (stat tile with trends)
VisualisationProgressOrb, ProgressRing, StatusPulse, StatusBadge
ActivityAgentNode, AgentActivityCard, ActivityTimeline, AgentThinkingIndicator
UtilityNotificationStream, ElapsedTimer
HooksuseElapsedTime, useCountdown, useStatusTransitions, useStatusColourTransition
UtilsformatElapsedAU, formatTimestampAU, formatDateAU, getAustralianTimezone

Dashboard Pages

PageLocationData Source
Agent Dashboardapps/web/app/(dashboard)/agents/page.tsx/api/agents/stats, /api/agents/list
Analytics Dashboardapps/web/app/dashboard-analytics/page.tsx/api/analytics/metrics/overview
Status Command CentreEmbedded componentSupabase Realtime (agent_runs table)

Backend APIs

RouteLocationReturns
/analytics/metrics/overviewapps/backend/src/api/routes/analytics.pyRuns, success rate, cost, tokens
/analytics/metrics/agentsSame filePer-agent performance breakdown
/analytics/metrics/costsSame fileCost by model, token breakdown
/api/agents/statsapps/backend/src/api/routes/agent_dashboard.pyAggregate agent statistics
/api/agents/{id}/healthSame fileAgentHealthReport model
/api/agents/performance/trendsSame fileTime-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:

StatusColourHSLAnimation
pendingSlatehsl(220 14% 46%)Pulse (idle)
in_progressBluehsl(217 91% 60%)Spin (active)
awaiting_verificationAmberhsl(38 92% 50%)Pulse (active)
verification_in_progressAmberhsl(38 92% 50%)Spin (active)
verification_passedGreenhsl(142 76% 36%)None (idle)
verification_failedRedhsl(0 84% 60%)Pulse (urgent)
completedEmerald#00FF88None (idle)
failedRed#FF4444Pulse (urgent)
blockedSlateMutedNone (idle)
escalated_to_humanMagenta#FF00FFPulse (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

NeedComponentImport From
Inline metrics rowDataStripstatus-command-centre
Single stat with trendMetricTilestatus-command-centre
Agent execution statusAgentNodestatus-command-centre
Circular progressProgressOrb or ProgressRingstatus-command-centre
Status dotStatusPulsestatus-command-centre
Status labelStatusBadgestatus-command-centre
Step timelineActivityTimelinestatus-command-centre
Notification sidebarNotificationStreamstatus-command-centre
Elapsed time counterElapsedTimerstatus-command-centre

---

Anti-Patterns

Anti-PatternWhy It FailsCorrect Approach
grid-cols-2 / grid-cols-4 metric cardsViolates Scientific Luxury layout rulesDataStrip or timeline layout
Standard <Card> with rounded-lgWrong corners, wrong aestheticrounded-sm border-[0.5px] border-white/[0.06]
CSS transition: all 0.3s linearBanned by Bezier (Council of Logic)Framer Motion with physics-based easing
White/light background dashboardsViolates OLED black requirementbg-[#050505] always
No loading skeletonLayout shift on data loadSkeleton matching final layout structure
No connection indicatorUsers cannot tell if data is liveConnectionIndicator in every realtime page
Hardcoded status coloursDrift from spectral palettegetStatusConfig(status).colour
setInterval without cleanupMemory leak on unmountuseEffect with clearInterval in cleanup

---

Checklist for New Dashboard Pages

Layout

  • [ ] OLED black background (bg-[#050505])
  • [ ] Timeline or orbital layout (no card grids)
  • [ ] DataStrip for summary metrics (not metric grid)
  • [ ] Single pixel borders (border-[0.5px] border-white/[0.06])
  • [ ] rounded-sm only (no rounded-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-collector MetricsRegistry for data source
  • [ ] Spectral colours from STATUS_CONFIG constants
  • [ ] 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

  • MetricsRegistry provides the data layer (counters, gauges, histograms)
  • Time-series aggregation powers trend charts
  • Summary endpoint feeds DataStrip and MetricTile components

State Machine

  • AgentRunStatus (10 states) maps directly to STATUS_CONFIG colour/animation entries
  • useStatusTransitions hook handles state change animations

Structured Logging

  • Dashboard pages log dashboard_loaded, dashboard_error events
  • Connection status changes logged for debugging

Cron Scheduler

  • Cron job metrics displayed via DataStrip or MetricTile
  • 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() and getAustralianTimezone()
  • Currency: AUD ($) — total_cost_usd converted to AUD for display
  • Spelling: colour, behaviour, analyse, optimise, centre
  • Footer: Australian date format in dashboard footers

Related skills

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.