Back to list
paulbreuler

runi-design

by paulbreuler

See the truth about your APIs runi is an open-source API client that verifies what AI generates. When 46% of developers don't trust AI output (Stack Overflow 2025 Developer Survey), you need a second opinion. runi is that opinion.

7🍴 0📅 Jan 24, 2026

SKILL.md


name: runi-design description: Build UI components and pages following the runi design system. Use this skill when creating React components for runi—the HTTP client that catches spec drift, verifies AI-generated code, and reveals cross-API relationships. Design language reflects runi's German Shepherd nature: vigilant, protective, with ambient intelligence through subtle signal dots that demand investigation.

runi Design System

This skill guides creation of UI components and pages that follow runi's design system.

Brand: runi is named after a German Shepherd—vigilant, protective, nose to the ground. The design reflects this: ambient intelligence through signal dots, deep inspection, tracking changes over time, and acting decisively with clear paths forward.

Tagline: "See the truth about your APIs"

Philosophy: "Collapse uncertainty into truth"

IMPORTANT: runi uses semantic CSS variables via Tailwind utility classes. Always use semantic color tokens (e.g., bg-background, text-foreground, bg-card) to ensure dark mode compatibility and consistent theming.

Tech Stack

ComponentTechnology
RuntimeTauri v2.9.x
BackendRust 1.80+
FrontendReact 19 + TypeScript 5.9
BuildVite 7.x
StylingTailwind CSS 4.x
AnimationMotion 12.x
RoutingReact Router 7.x
StateZustand
IconsLucide React

When to Use

  • Use this skill when creating or modifying React components, pages, or UI elements in runi
  • Use this skill when making design decisions about color, typography, spacing, or interactions
  • Use this skill when reviewing UI code to ensure it follows the design system
  • Use this skill when designing AI-native features that prioritize conversation over traditional UI patterns
  • Use this skill when you need guidance on when to use color vs. grayscale

Component Library Philosophy

Custom Components, Not External Libraries

If a component doesn't exist in a library that perfectly fits our design system, we design it ourselves as craftsmen and artists. We build our own custom component library that integrates seamlessly with runi's design system.

Key Principles:

  • Craftsmanship over convenience: We craft components that fit perfectly, not compromise with generic solutions
  • Design system integration: Every component respects our zen, calm, book-like aesthetic
  • Performance first: React frontend on Rust backend—components must be performant
  • Beauty and clarity: Components work with absolute clarity, not ambiguity

The Unreal Engine Metaphor: Think like game engine developers—craftsmanship, performance, clarity, not gamification. Game engines don't use generic UI libraries—they craft their own systems that fit perfectly within their architecture. We do the same.

See DESIGN_IDEOLOGY.md (read via mcp_runi_Planning_read_doc({ path: 'DESIGN_IDEOLOGY.md' })) for the complete craftsmanship philosophy, custom component library approach, and unified material feel principles.

Instructions

Design Philosophy: The German Shepherd

runi's design reflects its namesake—a German Shepherd. Vigilant. Protective. Nose to the ground. "Something's not right here."

The Design Language:

TraitDesign Expression
Vigilant, alertAmbient intelligence—subtle signal dots that demand investigation
ProtectiveCatches problems before they escape to production
Nose to the groundDeep inspection of requests, responses, schemas
Tracks everythingTemporal awareness—version history, diffs, change detection
Acts decisivelyNot just warnings—actionable fixes, clear paths forward

Core Principles:

  • Signal System: Yellow dots appear when something drifts. You investigate. You discover.
  • Strategic Color: Color is functional and semantic—HTTP methods, status codes, signals. Not decoration.
  • Progressive Revelation: Start simple, discover depth. Features reveal based on user behavior.
  • Dark Theme: Near-black backgrounds (#0a0a0a)—the night watch.
  • Quiet & Focused: Minimal visual noise. High contrast for readability.

NOT: Flashy animations, heavy UI chrome, color for decoration, overwhelming users with features

Color System: The Night Watch

runi Color Palette (from Brand Spirit v2.1):

Background (app):     #0a0a0a    Near-black—the night watch
Background (surface): #141414    Dark gray
Background (raised):  #1e1e1e    Elevated surfaces

Text (primary):       #f5f5f5
Text (secondary):     #a3a3a3
Text (muted):         #636363

Accent (primary):     #3b82f6    Blue—action, selection, focus
Accent (AI):          #a855f7    Purple—AI-generated content (suspect until verified)
Signal (success):     #22c55e    Green—valid, verified, safe
Signal (warning):     #f59e0b    Amber—drift detected, needs investigation
Signal (error):       #ef4444    Red—breaking change, critical threat

The Foundation: Most of runi's interface should be grayscale—using semantic grays for backgrounds, text, borders, and structure. Color is reserved for meaningful, functional elements that need to stand out.

Semantic Colors (Dark Mode Compatible):

Use these Tailwind classes for the grayscale foundation:

Tailwind ClassUsage
bg-background / text-foregroundPage backgrounds, primary text
bg-card / text-card-foregroundCards, elevated surfaces
bg-muted / text-muted-foregroundSecondary text, disabled states
bg-primary / text-primary-foregroundPrimary buttons, CTAs
bg-secondary / text-secondary-foregroundSecondary buttons
bg-accent / text-accent-foregroundHover states, highlights
bg-destructive / text-destructive-foregroundErrors, delete actions
border-borderBorders, dividers
bg-input / border-inputForm inputs, selectors
ring-ringFocus rings (default, use accent-blue explicitly)

Strategic Color: When and Where

Color should be used sparingly and purposefully. These are your "blue eyes" moments—elements that need to draw attention and convey meaning:

  1. HTTP Methods - Semantic, functional (they define what the request does)
  2. Status Codes - Semantic, functional (they communicate response state)
  3. Critical Feedback - Errors, warnings (they need immediate attention)
  4. AI Interactions - Prompts, suggestions, intelligence (this is the "conversation")
  5. Key Actions - Very sparingly, for primary CTAs only

Everything else should be grayscale using semantic tokens.

HTTP Method Colors (Strategic Splash #1):

HTTP methods get color because they're functional and semantic—they communicate meaning:

MethodText ColorBackground (for badges)Meaning
GETtext-accent-bluebg-accent-blue/10Read, safe
POSTtext-signal-successbg-signal-success/10Create, positive
PUTtext-signal-warningbg-signal-warning/10Update, caution
PATCHtext-signal-warningbg-signal-warning/10Update, caution
DELETEtext-signal-errorbg-signal-error/10Destructive
HEADtext-text-mutedbg-text-muted/10Meta/secondary
OPTIONStext-text-mutedbg-text-muted/10Meta/secondary

2026 Zen Aesthetic: Color the text, use subtle background tints. No solid colored backgrounds—muted surfaces with selective emphasis.

Signal Colors (from Design Vision v8.1):

SignalHexMeaning
Green#22c55eVerified, safe, all clear
Amber#f59e0bDrift detected, needs investigation
Red#ef4444Breaking change, critical issue
Purple#a855f7AI-generated (suspect until verified)
Blue#3b82f6Suggestion available

HTTP Status Code Colors (Strategic Splash #2):

Status codes get color because they're functional and semantic—they communicate response state:

RangeText ColorBackground (for badges)Meaning
2xxtext-signal-successbg-signal-success/10Success
3xxtext-accent-bluebg-accent-blue/10Redirects
4xxtext-signal-warningbg-signal-warning/10Client errors
5xxtext-signal-errorbg-signal-error/10Server errors
Othertext-text-mutedbg-text-muted/10Unknown

Strategic Color Guidelines:

// BAD - using color for decoration
<div className="bg-blue-500 text-white"> {/* Color without purpose */}
<button className="bg-purple-600">Secondary action</button> {/* Color for non-critical element */}

// BAD - hardcoded colors break dark mode
<div className="bg-white text-black">

// GOOD - grayscale foundation
<div className="bg-background text-foreground"> {/* Monochrome */}
<div className="bg-card border border-border"> {/* Semantic grays */}
<button className="bg-muted hover:bg-muted/80"> {/* Grayscale interaction */}

// GOOD - strategic color for meaning (using design system tokens)
<span className="text-accent-blue bg-accent-blue/10 px-1.5 py-0.5 rounded">GET</span> {/* HTTP method */}
<span className="text-signal-error">500</span> {/* Status code */}
<div className="bg-signal-error/10 border-signal-error/20 text-signal-error">Error</div> {/* Critical feedback */}

Key Rule: When in doubt, use grayscale. Color is reserved for signals that demand attention—drift warnings, verification status, HTTP methods.

Typography: Clean and Readable

Typography should be clear, readable, and purposeful. High contrast for readability in the dark theme.

Font Families:

/* Code and data (monospaced) */
font-family: 'JetBrains Mono', 'SF Mono', Consolas, monospace;

/* UI text (system fonts) */
font-family:
  Inter,
  -apple-system,
  BlinkMacSystemFont,
  sans-serif;

Type Hierarchy:

ElementFontWeightSizeUsage
HeadingsInterMediumtext-lgSection titles
UI TextInterRegulartext-smBody text, labels
Code/DataMonospaceRegulartext-smRequest/response content
Secondary TextInterRegulartext-xsMetadata, hints

Typography Patterns:

{
  /* UI Text */
}
<div className="text-sm text-foreground">UI Text</div>;

{
  /* Code/Data (always monospaced) */
}
<pre className="font-mono text-sm text-foreground bg-muted/30">Code</pre>;

{
  /* Secondary Text */
}
<span className="text-xs text-muted-foreground">Secondary info</span>;

{
  /* Headings */
}
<h3 className="text-lg font-medium text-foreground">Section Title</h3>;

Component Architecture

Import from UI Components:

Always use components from src/components/ui/:

import { Button } from '@/components/ui/button';
import { Card } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { cn } from '@/lib/utils';

Button Variants:

// Use these variants
variant: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link';
size: 'default' | 'sm' | 'lg' | 'icon';

Card Patterns:

  • Use rounded-xl for larger cards
  • Subtle borders: border border-border
  • Background: bg-card
  • Shadow: shadow-sm (subtle elevation)

Design Patterns

Rounded Corners:

runi uses consistent border radius:

  • Small elements: rounded-md (default)
  • Cards/containers: rounded-xl
  • Pill shapes: rounded-full (when needed)

Hover States:

{
  /* Subtle background change */
}
<div className="hover:bg-muted/50 transition-colors duration-200">Content</div>;

{
  /* Only use cursor-pointer on actual links/buttons */
}
<button className="cursor-pointer">Button</button>;

Key Rule: Only use cursor-pointer on actual clickable/interactive elements. Use hover:bg-muted/50 for hover feedback on list items and containers.

Transitions:

Always use smooth transitions for state changes:

  • Color transitions: transition-colors duration-200
  • All transitions: transition-all duration-200 ease-in-out
  • Standard duration: 200ms for smooth, responsive feel

Shadows:

Use subtle shadows for elevation:

  • shadow-xs - Buttons, inputs
  • shadow-sm - Cards, elevated surfaces
  • shadow-md - Modals, popovers (when needed)

Spacing:

  • Use consistent padding: p-4, p-6, p-8
  • Card gaps: gap-4 or gap-6
  • Section margins: my-4, my-6, my-8

React 19 + Motion 12 Patterns

Functional Components with TypeScript:

import { motion } from 'motion/react';
import { cn } from '@/lib/utils';

interface CardProps {
  title: string;
  description?: string;
  className?: string;
  onAction?: () => void;
}

export const Card = ({ title, description, className, onAction }: CardProps): JSX.Element => {
  return (
    <motion.div
      className={cn('p-6 bg-card border border-border rounded-xl', className)}
      whileHover={{ scale: 1.01 }}
      transition={{ duration: 0.2 }}
    >
      <h3 className="text-lg font-medium text-card-foreground mb-2">{title}</h3>
      {description && <p className="text-sm text-muted-foreground mb-4">{description}</p>}
      {onAction && (
        <Button variant="default" onClick={onAction}>
          Action
        </Button>
      )}
    </motion.div>
  );
};

Zustand Store Pattern:

import { create } from 'zustand';

interface RequestState {
  url: string;
  method: string;
  loading: boolean;
  setUrl: (url: string) => void;
  setMethod: (method: string) => void;
  setLoading: (loading: boolean) => void;
}

export const useRequestStore = create<RequestState>((set) => ({
  url: '',
  method: 'GET',
  loading: false,
  setUrl: (url) => set({ url }),
  setMethod: (method) => set({ method }),
  setLoading: (loading) => set({ loading }),
}));

Required:

  • TypeScript on all components
  • Explicit return types on functions
  • Use Zustand for global state, useState for local state
  • Type all props with interfaces

Motion 12 Animation:

import { motion, AnimatePresence } from 'motion/react';

// Animated element
<motion.div
  initial={{ opacity: 0, y: 20 }}
  animate={{ opacity: 1, y: 0 }}
  exit={{ opacity: 0, y: -20 }}
  transition={{ duration: 0.2 }}
>
  Content
</motion.div>

// AnimatePresence for enter/exit
<AnimatePresence mode="wait">
  {isVisible && (
    <motion.div key="modal" /* ... */>
      Modal content
    </motion.div>
  )}
</AnimatePresence>

Component Construction Patterns

Building New Components:

import { motion } from 'motion/react';
import { Button } from '@/components/ui/button';
import { cn } from '@/lib/utils';

interface RequestCardProps {
  title: string;
  method: string;
  url: string;
  className?: string;
  onSend?: () => void;
}

export const RequestCard = ({
  title,
  method,
  url,
  className,
  onSend,
}: RequestCardProps): JSX.Element => {
  // Strategic color: HTTP method gets color (functional/semantic)
  // Using design system tokens for consistency
  const methodTextColors: Record<string, string> = {
    GET: 'text-accent-blue',
    POST: 'text-signal-success',
    PUT: 'text-signal-warning',
    PATCH: 'text-signal-warning',
    DELETE: 'text-signal-error',
  };
  const methodBgColors: Record<string, string> = {
    GET: 'bg-accent-blue/10',
    POST: 'bg-signal-success/10',
    PUT: 'bg-signal-warning/10',
    PATCH: 'bg-signal-warning/10',
    DELETE: 'bg-signal-error/10',
  };
  const textColor = methodTextColors[method] || 'text-text-muted';
  const bgColor = methodBgColors[method] || 'bg-text-muted/10';

  return (
    <motion.div
      className={cn('p-4 bg-card border-border rounded-xl', className)}
      whileHover={{ scale: 1.005 }}
    >
      <h3 className="text-base font-medium text-card-foreground">{title}</h3>
      <div className="flex items-center gap-2 mt-2">
        {/* Strategic splash: method color (zen aesthetic - text color with subtle bg) */}
        <span
          className={cn(
            'px-1.5 py-0.5 rounded text-xs font-semibold font-mono',
            textColor,
            bgColor
          )}
        >
          {method}
        </span>
        {/* Grayscale: URL (monochrome) */}
        <code className="flex-1 text-sm font-mono text-foreground bg-muted/30 px-2 py-1 rounded">
          {url}
        </code>
        {/* Grayscale: Button (semantic, not colored) */}
        {onSend && (
          <Button variant="outline" size="sm" onClick={onSend}>
            Send
          </Button>
        )}
      </div>
    </motion.div>
  );
};

Accessibility Patterns:

  • Always include proper aria attributes
  • Use semantic HTML (<nav>, <main>, <aside>)
  • Focus management with proper tabIndex

Focus Ring Standard:

All interactive elements must have visible focus indicators that meet WCAG 2.1 AA requirements:

  • Color: accent-blue (oklch(0.623 0.214 259.1)) - aligns with design system "Blue—action, selection, focus"
  • Width: 2px (ring-2)
  • Offset: 2px (ring-offset-2)
  • Offset Color: bg-app (ring-offset-bg-app)
  • Pseudo-class: :focus-visible (only shows on keyboard focus, not mouse clicks)

Tailwind Classes:

'outline-none focus-visible:ring-2 focus-visible:ring-accent-blue focus-visible:ring-offset-2 focus-visible:ring-offset-bg-app';

Reusable Utility: Use focusRingClasses from @/utils/accessibility for consistency.

Hover-Only Elements: Use useFocusVisible hook from @/utils/accessibility for elements that are hidden by default and shown on hover, but must be visible when focused.

Error Handling:

Always display Rust/Tauri errors in UI:

{
  error && (
    <div className="p-4 bg-destructive/10 border border-destructive/20 rounded-lg text-destructive">
      {error}
    </div>
  );
}

Implementation Checklist

  1. Default to grayscale - Use semantic grays (bg-background, bg-card, text-foreground, bg-muted) for most UI
  2. Color is strategic - Only use color for HTTP methods, status codes, critical feedback, AI interactions, and key actions
  3. Never hardcode colors - No bg-white, text-black, blue-500 (use semantic tokens or strategic color utilities)
  4. Test dark mode - All components must work in both light and dark modes
  5. Use UI components - Import from @/components/ui/
  6. Use React 19 patterns - Functional components, hooks, TypeScript
  7. Use Zustand for global state - Not Redux, not Context for shared state
  8. Type everything - TypeScript strict mode, explicit types
  9. Smooth transitions - 200ms duration, transition-colors for hover
  10. No pointer cursor on non-clickable - Only use cursor-pointer on actual buttons/links
  11. Monospaced fonts for code/data - Use font-mono for request/response content
  12. Display errors - Always show Tauri command errors in UI
  13. Use Motion for animations - Import from motion/react, not framer-motion

Example Components

HTTP Method Badge:

import { cn } from '@/lib/utils';

interface MethodBadgeProps {
  method: string;
  className?: string;
}

// Design system colors - text with subtle background (zen aesthetic)
const methodTextColors: Record<string, string> = {
  GET: 'text-accent-blue',
  POST: 'text-signal-success',
  PUT: 'text-signal-warning',
  PATCH: 'text-signal-warning',
  DELETE: 'text-signal-error',
  HEAD: 'text-text-muted',
  OPTIONS: 'text-text-muted',
};

const methodBgColors: Record<string, string> = {
  GET: 'bg-accent-blue/10',
  POST: 'bg-signal-success/10',
  PUT: 'bg-signal-warning/10',
  PATCH: 'bg-signal-warning/10',
  DELETE: 'bg-signal-error/10',
  HEAD: 'bg-text-muted/10',
  OPTIONS: 'bg-text-muted/10',
};

export const MethodBadge = ({ method, className }: MethodBadgeProps): JSX.Element => {
  const textColor = methodTextColors[method] ?? 'text-text-muted';
  const bgColor = methodBgColors[method] ?? 'bg-text-muted/10';

  return (
    <span
      className={cn(
        'px-1.5 py-0.5 rounded text-xs font-semibold font-mono',
        textColor,
        bgColor,
        className
      )}
    >
      {method}
    </span>
  );
};

Status Badge:

import { cn } from '@/lib/utils';

interface StatusBadgeProps {
  status: number;
  className?: string;
}

// Design system colors - text only for zen aesthetic
const getStatusColor = (status: number): string => {
  if (status >= 200 && status < 300) return 'text-signal-success';
  if (status >= 300 && status < 400) return 'text-accent-blue';
  if (status >= 400 && status < 500) return 'text-signal-warning';
  if (status >= 500) return 'text-signal-error';
  return 'text-text-muted';
};

export const StatusBadge = ({ status, className }: StatusBadgeProps): JSX.Element => {
  const colorClass = getStatusColor(status);

  return (
    <span className={cn('text-sm font-mono font-semibold', colorClass, className)}>{status}</span>
  );
};

AI Interaction (The "Blue Eyes" Moment):

AI prompts and suggestions are where color can shine—this is the conversational, intelligent moment:

import { Button } from '@/components/ui/button';
import { motion } from 'motion/react';

interface AISuggestionProps {
  suggestion: string;
  onAccept?: () => void;
}

export const AISuggestion = ({ suggestion, onAccept }: AISuggestionProps): JSX.Element => {
  return (
    <motion.div
      className="bg-primary/5 border-primary/20 border rounded-lg p-3"
      initial={{ opacity: 0, y: 10 }}
      animate={{ opacity: 1, y: 0 }}
    >
      <p className="text-sm text-foreground mb-2">{suggestion}</p>
      {/* Primary action: strategic color */}
      <Button variant="default" size="sm" onClick={onAccept}>
        Use suggestion
      </Button>
    </motion.div>
  );
};

For detailed technical implementation, use MCP tools to read planning documents:

  • Design Ideology: Read via mcp_runi_Planning_read_doc({ path: 'DESIGN_IDEOLOGY.md' }) - Craftsmanship philosophy, custom component library approach, Unreal Engine metaphor
  • Design Vision: Read via mcp_runi_Planning_read_doc({ path: 'runi-design-vision-v8.1.md' })
  • Component Library: src/components/ui/
  • Stores: src/stores/
  • CSS Variables: src/index.css
  • Tauri Commands: src-tauri/src/commands/
  • Project Structure: CLAUDE.md

Score

Total Score

75/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

+10
人気

GitHub Stars 100以上

0/15
最近の活動

1ヶ月以内に更新

+10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

+5

Reviews

💬

Reviews coming soon