A design language for premium, dark-themed knowledge interfaces.
"Numbers are heroes, labels are whispers."
This system creates interfaces that feel like high-end personal analytics—calm, confident, and data-forward. Think Oura Ring, Arc Browser, Linear. The design should feel expensive without being flashy.
- Hierarchy through restraint — Size and opacity create importance, never color
- Data speaks first — Large metrics dominate, supporting text recedes
- Sequential revelation — Elements wake up one by one, never all at once
- Confident emptiness — Whitespace is intentional, not leftover
- Invisible interaction — Hover states reveal, not decorate
- No Emojis — Icons and typography convey meaning instead
- No Accent Colors — Monochromatic only (except entity graph)
- No Gradients — Flat colors with opacity variations
- No Bold for Emphasis — Size differential handles hierarchy
- No Skeleton Loaders — Staggered reveals instead
The palette moves from near-black backgrounds through ascending grays to white text. No accent colors. No gradients. No color-coding for categories or status.
/* Backgrounds (darkest to lightest) */
bg-neutral-950 /* Main app background (#0a0a0a) */
bg-neutral-900/80 /* Sidebar, primary cards */
bg-neutral-900/60 /* Card backgrounds, containers */
bg-neutral-900/50 /* Overlay backgrounds */
bg-neutral-900/40 /* Light cards, questionnaire cards */
bg-neutral-800/60 /* Active states, icon containers */
bg-neutral-800/50 /* Hover states for cards */
bg-neutral-800/40 /* Selected cards, hover backgrounds */
bg-neutral-800/30 /* Subtle hover backgrounds */
bg-neutral-800/20 /* Very subtle hover states */
bg-neutral-800 /* Badges, tags, solid elements */
bg-neutral-700 /* Active pills, progress bars */
/* Borders */
border-neutral-800/60 /* Subtle borders (panels) */
border-neutral-800 /* Default borders */
border-neutral-700 /* Hover states, active states */
border-neutral-600 /* Focus/highlight states */
/* Text Hierarchy (5 opacity levels) */
text-white /* Primary text, hero numbers, titles */
text-neutral-200 /* Secondary text, descriptions */
text-neutral-300 /* Body text, markdown content */
text-neutral-400 /* Muted text, icons, timestamps */
text-neutral-500 /* Timestamps, hints, labels */
text-neutral-600 /* Placeholders, very muted text *//* Border Beams */
from-transparent via-neutral-500 to-transparent /* Modal beam */
from-neutral-600/40 via-neutral-500/40 to-neutral-600/40 /* Standard beam */
from-neutral-600/30 via-neutral-400/40 to-neutral-600/30 /* Selection beam */
/* Glare Effects */
rgba(255,255,255,0.15) /* Glare center */
rgba(255,255,255,0.05) /* Glare mid */
rgba(255,255,255,0) /* Glare edge */
/* Destructive (delete actions only) */
hover:bg-red-500/20
hover:text-red-400
hover:border-red-500/40The entity graph is the one place where color appears. Node types have distinct but muted, desaturated colors that feel cohesive with the monochromatic system.
Light, not bold. Large numbers and headlines use light font weights. This creates elegance at scale.
font-light /* Hero stats (3xl-6xl numbers), main titles - PREFERRED for large text */
font-normal /* Body text default */
font-medium /* Item titles, badges, buttons */
font-semibold /* Important labels, type tags, markdown headings */
/* font-bold is avoided for emphasis — size handles hierarchy */text-[9px] /* Very small labels */
text-[10px] /* Tags, timestamps, progress indicators */
text-[11px] /* Small metadata, source labels */
text-xs /* Descriptions, metadata (12px) */
text-sm /* Item titles, body text (14px) */
text-base /* Modal titles, section headers (16px) */
text-lg /* Page titles (18px) */
text-xl /* Card titles on hover */
text-2xl /* Activity totals */
text-3xl-6xl /* Hero stats (responsive) */Uppercase whispers. Section labels are small, uppercase, and widely tracked.
tracking-tight /* Hero stats, main numbers */
tracking-wide /* Body text emphasis */
tracking-wider /* Labels ("14-Day Activity") */
tracking-widest /* Uppercase labels ("Step 1 of 5") */
tracking-[0.2em] /* Questionnaire progress labels */uppercase /* Tags, type badges, progress labels, section headers */
capitalize /* Chat titles */
lowercase /* Formatting normalization */| Element | Size | Weight | Color | Tracking |
|---|---|---|---|---|
| Hero numbers | 3xl-6xl | light | white | tight |
| Page titles | lg-xl | light | white | normal |
| Card counts | 2xl | light | white | tight |
| Section labels | xs | medium | neutral-500 | widest, uppercase |
| Body text | sm | normal | neutral-300 | normal |
| Metadata | [10px]-xs | normal | neutral-500 | normal |
When a view loads, elements appear sequentially—hero content first, then supporting sections, then list items one by one. The interface "wakes up."
[0.25, 0.46, 0.45, 0.94] /* Main page transitions (smooth deceleration) */
[0.25, 0.1, 0.25, 1] /* Questionnaire animations */
[0.4, 0, 0.2, 1] /* Accordion expand/collapse */
[0.16, 1, 0.3, 1] /* GlowingEffect movement */
type: "spring" /* Tabs, modals (bounce: 0.2-0.3, stiffness: 260, damping: 15) */Headlines and pages animate from blurred to sharp. This creates a sense of focus emerging.
initial={{ opacity: 0, filter: 'blur(10px)' }}
animate={{ opacity: 1, filter: 'blur(0px)' }}
exit={{ opacity: 0, filter: 'blur(5px)' }}
transition={{ duration: 0.4, ease: [0.25, 0.46, 0.45, 0.94] }}Words animate in with staggered blur-to-clear:
initial={{ opacity: 0, filter: 'blur(8px)' }}
animate={{ opacity: 1, filter: 'blur(0px)' }}
stagger: 0.08s (fast) or 0.2s (dramatic)
duration: 0.4s// Standard entry
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
transition={{ duration: 0.3, delay: index * 0.05 }} /* Stagger by index */
// Hover
whileHover={{ scale: 1.01 }} /* Subtle lift */
whileHover={{ scale: 1.02 }} /* Compact cards */initial={{ height: 0, opacity: 0 }}
animate={{ height: "auto", opacity: 1 }}
exit={{ height: 0, opacity: 0 }}
transition={{ duration: 0.3, ease: [0.4, 0, 0.2, 1] }}initial={{ opacity: 0, scale: 0.5, rotateX: 40, y: 40 }}
animate={{ opacity: 1, scale: 1, rotateX: 0, y: 0 }}
exit={{ opacity: 0, scale: 0.8, rotateX: 10 }}
transition={{ type: "spring", stiffness: 260, damping: 15 }}layoutId="activeTab"
transition={{ type: "spring", bounce: 0.2, duration: 0.6 }}Numbers count up. Things build rather than appear.
duration: 1000ms
steps: 30
increment: value / stepsinitial={{ width: 0 }}
animate={{ width: `${percentage}%` }}
transition={{ duration: 0.6, ease: [0.25, 0.1, 0.25, 1] }}
// Activity bars (staggered)
transition={{ duration: 0.5, delay: 0.8 + idx * 0.04 }}// Spinner
"w-6 h-6 border-2 border-neutral-600 border-t-transparent rounded-full animate-spin"
// Rotating refresh
className={cn("w-5 h-5", loading && "animate-spin")}
// Disabled
"opacity-50 cursor-not-allowed"Animated border effect that travels around card edges. A traveling highlight that adds premium feel without color.
// Modal beam (prominent)
<BorderBeam duration={4-6} size={380-400} borderWidth={2}
className="from-transparent via-neutral-500 to-transparent" />
// Card selection beam (subtle)
<BorderBeam size={150} duration={8} borderWidth={1}
className="from-neutral-600/30 via-neutral-400/40 to-neutral-600/30" />
// Double beam effect (staggered)
<BorderBeam duration={4} delay={0} size={400} borderWidth={2} />
<BorderBeam duration={4} delay={1} size={400} borderWidth={2} />Essential component for scroll containers. Creates depth by fading content at edges.
<ProgressiveBlur
height="60px" /* 60-80px typical */
position="bottom" /* or "top" */
className="pointer-events-none"
/>Required for all scrollable containers:
<div className="relative flex-1 min-h-0">
<div className="absolute inset-0 overflow-y-auto pb-16">
{/* Scrollable content */}
</div>
<ProgressiveBlur height="80px" position="bottom" className="pointer-events-none" />
</div>Premium hover effect with perspective rotation and light reflection.
// 3D rotation based on mouse position
transform: `perspective(800px) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`
rotateY: ((x - 50) / 50) * 3 /* max 3 degrees */
rotateX: ((y - 50) / 50) * -2 /* max 2 degrees, inverted */
transition: 'transform 0.2s ease-out'
// Glare overlay gradient (follows cursor)
background: `radial-gradient(circle at ${x}% ${y}%,
rgba(255,255,255,0.15) 0%,
rgba(255,255,255,0.05) 40%,
rgba(255,255,255,0) 70%)`
opacity: 0.15 (on hover)
// Shimmer layer
mix-blend-mode: overlay
opacity: glareStyle.opacity * 1.5When one card is hovered, siblings blur to create focus.
const isBlurred = hoveredIndex !== null && hoveredIndex !== index;
className={cn(
"transition-all duration-300 ease-out",
isBlurred && "blur-sm scale-[0.98] opacity-60"
)}Dramatic lighting effect. Used exclusively in onboarding for hero moments.
Animated orbiting elements. Used in onboarding to show supported AI platforms.
Ambient background effects. Always at z-0, content at z-10+.
Staggered word-by-word text reveal animation with blur-to-clear.
Sections have significant vertical spacing. Cards have comfortable internal padding. Lists have relaxed row heights.
/* Spacing Scale */
gap-2 /* Icon buttons, small elements */
gap-3 /* Item groups, navigation */
gap-4 /* Dashboard cards */
gap-6 /* Page sections */
/* Padding Scale */
p-2 / p-2.5 /* Small items */
p-3 /* Compact cards */
p-4 /* Standard cards */
p-5 /* Questionnaire cards */
p-6 /* Page padding, modal content */rounded-lg /* Small cards, buttons (8px) */
rounded-xl /* Standard cards (12px) */
rounded-2xl /* Large cards, modals (16px) */
rounded-full /* Pills, tabs, badges */Content cards arrange in flexible grids—not rigid columns. Cards can span different widths.
// ChatDetail example
Summary: ~50% height
Memories + Entities: split remaining 50% side-by-side
// Expandable sections with smooth transitionsLists on the left, detail on the right. The selected state is subtle—a slightly lighter background or border change.
All scrollable lists must have ProgressiveBlur:
<div className="relative flex-1 min-h-0">
<div className="absolute inset-0 overflow-y-auto pb-16">
{/* Content with adequate bottom padding */}
</div>
<ProgressiveBlur
height="80px"
position="bottom"
className="pointer-events-none absolute bottom-0 left-0 w-full"
/>
</div>Page titles stay visible. Counts update in headers so users always know where they are.
- React - UI framework
- TypeScript - Type safety
- Tailwind CSS - Utility-first styling
- motion/react (Framer Motion) - Animations
- Aceternity UI - Premium UI components
- react-markdown - Markdown rendering
- Tabler Icons - Icon library
- Lucide React - Additional icons
- Electron - Desktop application framework
- better-sqlite3 - SQLite database
- electron-vite - Build tooling
The app monitors and extracts conversations from:
- Claude (Desktop & Web)
- ChatGPT
- Gemini
- Perplexity
- Grok
// Border brightens
hover:border-neutral-700 /* From border-neutral-800 */
// Background shifts
hover:bg-neutral-800/60
hover:bg-neutral-800/50
hover:bg-neutral-800/40
hover:bg-neutral-800/30
hover:bg-neutral-800/20
// Text brightens
hover:text-white /* From text-neutral-400 */
hover:text-neutral-300 /* From text-neutral-500 */
// Subtle scale
whileHover={{ scale: 1.01 }}Interactive elements show affordances on hover—arrows appear, text brightens, borders highlight.
// Arrow/icon fade in
opacity-0 group-hover:opacity-100 transition-opacity
// Action hints appear
className="opacity-0 group-hover:opacity-100"focus:outline-none
focus:border-neutral-600 /* Input fields */
focus:ring-1 focus:ring-neutral-500/50 /* Dropdowns */
focus-visible:ring-2 focus-visible:ring-neutral-500/40 /* Cards */Subtle—a slightly lighter background or border change.
// Selected card
"bg-neutral-800/40 border-neutral-700"
// With BorderBeam
{isSelected && <BorderBeam size={150} duration={8} borderWidth={1} />}
// Highlight ring
"ring-2 ring-neutral-500 ring-offset-2 ring-offset-neutral-950"hover:bg-red-500/20
hover:text-red-400
hover:border-red-500/40Cards are containers, not decorations. Subtle borders, transparent backgrounds, comfortable padding.
// Standard card
"bg-neutral-900/60 border border-neutral-800 rounded-xl p-4 hover:border-neutral-700"
// Featured card (with beam)
<div className="relative bg-neutral-900/60 border border-neutral-800 rounded-xl p-4">
{content}
<BorderBeam size={200} duration={10} borderWidth={1.5} />
</div>
// Item variants
default: "border-neutral-800 bg-neutral-900/50 hover:bg-neutral-900/80"
outline: "border-neutral-800 bg-transparent hover:bg-neutral-900/30"
muted: "border-neutral-800/60 bg-neutral-900/30 hover:bg-neutral-900/60"List items have generous vertical padding and hairline dividers. Last item has no divider.
// List item
"p-4 border-b border-neutral-800/50 last:border-b-0 hover:bg-neutral-800/30"
// With hover arrow
<div className="group flex items-center justify-between">
<span>{title}</span>
<IconArrowRight className="w-4 h-4 opacity-0 group-hover:opacity-100 transition-opacity" />
</div>Large numbers centered with tiny labels beneath. Numbers animate up from zero.
<div className="text-center">
<AnimatedCounter value={count} className="text-4xl font-light text-white tracking-tight" />
<span className="text-xs text-neutral-500 uppercase tracking-widest">Label</span>
</div>// Type tag (uppercase)
"px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wider rounded-full bg-neutral-800 text-neutral-300 border border-neutral-700"
// Count pill
"px-2 py-0.5 rounded-full bg-neutral-800 text-neutral-400 border border-neutral-700"
// Simple badge
"px-1.5 py-0.5 rounded bg-neutral-800/50 text-neutral-600"// Primary button
"bg-neutral-800 border border-neutral-700 text-white hover:bg-neutral-700 hover:border-neutral-600 rounded-lg px-4 py-2"
// Icon button (square)
"h-8 w-8 rounded-lg border border-neutral-800 bg-neutral-900 text-neutral-400 hover:text-white hover:border-neutral-700"
// Panel button (larger)
"h-[42px] w-[42px] rounded-xl border border-neutral-800/60 bg-neutral-900/50"// Text input
"w-full pl-10 pr-4 py-3 rounded-xl bg-neutral-900/80 border border-neutral-800 text-white placeholder-neutral-600 focus:outline-none focus:border-neutral-600 transition-colors"
// Search with icon
<div className="relative">
<IconSearch className="absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-neutral-500" />
<input className="pl-10 ..." placeholder="Search..." />
</div>Pill-style with subtle backgrounds. Active state has sliding indicator.
// Tab bar
"flex gap-1 p-1 rounded-full bg-neutral-900/60 border border-neutral-800"
// Tab item
"px-4 py-2 rounded-full text-sm transition-colors"
// Active: with layoutId indicator
// Inactive: "text-neutral-400 hover:text-neutral-200"
// Active indicator
<motion.div layoutId="activeTab" className="absolute inset-0 bg-neutral-800/80 rounded-full" />Centered card on dimmed backdrop. Simple header with title and close.
// Backdrop
"fixed inset-0 bg-black/60 backdrop-blur-sm z-50"
// Modal container
"bg-neutral-900 border border-neutral-800 rounded-2xl p-6 max-w-lg w-full"
// With animation
initial={{ opacity: 0, scale: 0.5, rotateX: 40, y: 40 }}
animate={{ opacity: 1, scale: 1, rotateX: 0, y: 0 }}Centered icon in a rounded container, title below, description beneath.
<div className="h-full flex flex-col items-center justify-center text-center px-4">
<div className="w-16 h-16 rounded-2xl bg-neutral-800 border border-neutral-700 flex items-center justify-center mb-4">
<Icon className="w-8 h-8 text-neutral-600" />
</div>
<p className="text-neutral-400 text-lg font-medium mb-2">Title</p>
<p className="text-neutral-600 text-sm max-w-md">Description</p>
</div>Minimal. No gridlines, no axis labels, no legends unless essential.
// Activity bar
"h-full bg-neutral-700 rounded-sm"
initial={{ height: 0 }}
animate={{ height: `${value}%` }}
// Distribution bar (horizontal)
<div className="flex h-2 rounded-full overflow-hidden bg-neutral-800">
{segments.map((s, i) => (
<div
key={i}
className="h-full"
style={{
width: `${s.percent}%`,
backgroundColor: `rgba(255,255,255,${0.6 - i * 0.15})` /* Descending grays */
}}
/>
))}
</div>All scrollable content requires ProgressiveBlur:
<div className="relative flex-1 min-h-0">
<div className="absolute inset-0 overflow-y-auto pb-16">
{/* Content */}
</div>
<ProgressiveBlur height="80px" position="bottom" className="pointer-events-none" />
</div>- Collapsible sidebar using Aceternity Sidebar component
- Icon + label with animated show/hide
- Active state:
bg-neutral-800 text-white - Hover state:
bg-neutral-800/50 hover:text-white
App.tsx
├── StarsBackground (z-0)
├── ShootingStars (z-0)
├── Sidebar
│ └── SidebarBody (navigation items)
├── Tab Bar
└── Content Area (AnimatePresence, z-10)
├── Dashboard
├── ChatList → ChatDetail
├── MemoryList
├── EntityList
├── EntityGraph
└── MemoryChat
- Sparse and functional—icons appear for navigation, actions, and metadata counts
- They never decorate
- Small and muted by default, brightening on hover or when active
w-4 h-4 /* Inline icons, metadata */
w-5 h-5 /* Interactive icons, buttons */
w-6 h-6 /* Navigation icons */
w-8 h-8 /* Empty state icons */Long titles truncate with ellipsis. Long descriptions clamp to 2-3 lines.
truncate /* Single line ellipsis */
line-clamp-2 /* 2 lines max */
line-clamp-3 /* 3 lines max */Large numbers use locale formatting (commas/periods). Numbers in tables align with tabular figures.
Relative when recent: "2 hours ago" not "1/20/2026, 2:00 PM" for recent items. Full timestamps for older content.
The interface speaks quietly:
- Labels are terse: "Memories" not "Your Saved Memories"
- Descriptions are brief
- Empty states are encouraging but not chatty
- Error messages are clear and actionable
- Nothing is exclamatory
Before considering a screen complete:
- Does hierarchy come from size and opacity alone?
- Are large numbers using light weight, not bold?
- Are labels small, uppercase, and widely tracked?
- Is metadata appropriately tiny?
- Do animations stagger sequentially?
- Do hover states reveal rather than decorate?
- Is there generous whitespace between sections?
- Are there zero accent colors (except graph nodes)?
- Do all scroll containers have ProgressiveBlur?
- Do cards have the 3D glare effect on hover?
- Is the overall feeling calm and premium?
- Monochromatic grays from near-black to white
- Light font weights for large text
- Uppercase labels with wide letter-spacing
- Semi-transparent backgrounds
- Subtle, barely-visible borders
- Staggered sequential animations
- Blur-to-clear text reveals
- Growing bars and counting numbers
- Hover states that brighten or reveal
- Generous whitespace
- ProgressiveBlur on all scroll containers
- 3D card glare effects
- BorderBeam for featured/selected cards
- Muted categorical colors in the graph only
- Accent colors for emphasis or status
- Gradients anywhere
- Bold text for emphasis
- Heavy or prominent borders
- Solid opaque card backgrounds
- Simultaneous animations (everything at once)
- Decorative icons
- Skeleton loading states
- Complex loading indicators
- Emojis
- Color-coded badges or tags (except graph node types)
- Gridlines or axis labels on charts
- Drop shadows (except very subtle on modals)
className="bg-neutral-800 text-neutral-400 border border-neutral-700"className="px-2 py-0.5 rounded-full text-[10px] font-medium bg-neutral-700 text-neutral-300"className="px-2 py-0.5 text-[10px] font-semibold uppercase rounded bg-neutral-800 text-neutral-400 border border-neutral-700"className="bg-neutral-900/80 border border-neutral-800 text-white placeholder-neutral-600 focus:outline-none focus:border-neutral-600"className="bg-neutral-800 border border-neutral-700 text-white hover:bg-neutral-700 hover:border-neutral-600"className="p-2 rounded-lg bg-neutral-800 text-neutral-400 hover:text-white hover:bg-neutral-700"Centered layout with muted icon and text:
<div className="h-full flex flex-col items-center justify-center text-center px-4">
<div className="w-16 h-16 rounded-2xl bg-neutral-800 border border-neutral-700 flex items-center justify-center mb-4">
<Icon className="w-8 h-8 text-neutral-600" />
</div>
<p className="text-neutral-400 text-lg font-medium mb-2">Title</p>
<p className="text-neutral-600 text-sm max-w-md">Description</p>
</div>- Consistency - Always use the neutral palette, never introduce colors
- Hierarchy - Use opacity and size to create visual hierarchy, not color
- Animations - Keep animations subtle (0.3-0.5s), use blur-to-clear for polish
- Spacing - Use consistent padding (p-4 for cards, p-6 for page content)
- Borders - Default
border-neutral-800, hoverborder-neutral-700 - Backdrop Blur - Use
backdrop-blur-xlorbackdrop-blur-smfor depth - Z-Index - Stars at z-0, content at z-10, overlays higher
- Scroll - Always add ProgressiveBlur to scrollable containers
- Cards - Add 3D glare effect for premium feel
- Selection - Use BorderBeam for selected/featured items