Aurora is the operator-grade design system that powers Labby and the broader Lab gateway-admin surfaces. It is published as a shadcn-compatible registry at aurora.tootie.tv and lives in source at ~/workspace/aurora-design-system. Use it whenever you're producing React/Next.js UI that should look like it belongs in that family.
If the user invokes this skill without a concrete build target, ask what surface they want designed or implemented and whether the output should be production code, a static HTML artifact, or a mock/prototype. Keep the questions short, then proceed as an expert designer once the target is clear.
The non-negotiables Aurora gives you and that every consumer must respect:
- Dark-first, navy lift tiers — flat page, raised toolbars/headers, strongly raised inspector panels
- Cyan primary accent, rose secondary, violet for AI/automation identity, muted status colors (never neon)
- Manrope for display, Inter for working UI, JetBrains Mono only for code/paths/IDs/hashes
- Tokenized everything via
--aurora-*CSS custom properties — never inline hex in product code - Selection and focus are border + glow, not flooded fills
- Sentence case copy, matter-of-fact status text, no marketing voice
- Lucide line icons only, 14-18px, stroke 1.5-1.75px — no emoji as UI
When you're working inside the source repo
Source-of-truth files in ~/workspace/aurora-design-system:
registry/aurora/styles/aurora.css— canonical token bridge, semantic CSS variables, type classes,.aurora-page-shell,.aurora-nav-shell. Read this before claiming a token exists.registry/aurora/ui/*.tsx— 64 stable React primitives.registry/aurora/blocks/<domain>/<name>/*.tsx— composed product blocks (ai, auth, feedback, files, navigation, workspace).registry.json— shadcn registry source. Read this before claiming registry status or counts.public/r/registry.jsonandpublic/r/aurora-*.json— generated output. Stale untilpnpm registry:buildruns.app/gallery/[section]/page.tsx— gallery routes and live demos. Verify exact route inventory here, not from memory.app/globals.css— importsregistry/aurora/styles/aurora.css.
Derive counts, route lists, and component inventories from these files — do not hard-code them in commits or PR descriptions. The "Component inventory" section below is a category map for orienting, not a count source.
When you're consuming Aurora in another project
Install the token layer first, then any component:
# Token layer (required — every component reads from these vars)
npx shadcn@latest add https://aurora.tootie.tv/r/aurora-tokens.json
# Then any component
npx shadcn@latest add https://aurora.tootie.tv/r/aurora-button.json
Or register the namespace once in your components.json:
{
"registries": {
"@aurora": "https://aurora.tootie.tv/r/{name}.json"
}
}
Then npx shadcn@latest add @aurora/aurora-tokens and @aurora/aurora-<name>.
Required setup in the consuming app:
/* app/globals.css */
@import "../registry/aurora/styles/aurora.css";
// app/layout.tsx — load fonts and default to dark
import { Manrope, Inter, JetBrains_Mono } from "next/font/google"
<html lang="en" className="dark">
Toggle light with document.documentElement.classList.toggle("light") and remove "dark". Both modes must remain usable — verify the surface in .light before shipping.
When you're making static artifacts
For slides, mocks, throwaway prototypes, design reviews, and other non-production visual artifacts, create a static HTML file the user can open directly unless the artifact genuinely needs a dev server.
- Load Manrope, Inter, and JetBrains Mono from Google Fonts.
- Include the Aurora token layer in the artifact folder: copy the source CSS when available, or embed only the required token/type/page-shell CSS for a self-contained mock.
- Default to dark mode with
<html class="dark">and put the main canvas on<body class="aurora-page-shell">or a top-level.aurora-page-shellwrapper. - Copy any needed brand assets into the artifact directory and reference them locally. Do not hotlink, redraw, or approximate the Labby mark when a real asset exists.
- Use Lucide icons through the web package/CDN or inline icon markup that matches Lucide stroke rules: 14-18px,
currentColor, 1.5-1.75 stroke. - Keep the artifact faithful to Aurora's production rules: tokenized colors, Tier 2 panels, border + glow selection, sentence case copy, muted status colors, and no emoji.
- If you create an HTML artifact, tell the user the local path and whether it is static-openable or served by a dev server.
Tokens — never raw hex
Reach for semantic Aurora vars, or color-mix(in srgb, var(--aurora-accent-primary) 14%, transparent) for tinted fills. Full list and light/dark values in references/tokens.md; headline shape:
For non-web surfaces (Zed, Claude Code CLI, terminals, shell tools) the cyan/rose diverge into separate brighter tiers — see
references/editor-cli-tokens.md. The values below are the web canonical palette; don't paste them into a.tmTheme/Zed theme or vice-versa.
Surfaces
| Token | Purpose |
|---|---|
--aurora-page-bg |
Page background (apply via .aurora-page-shell) |
--aurora-nav-bg |
Sidebars, nav rails (apply via .aurora-nav-shell) |
--aurora-panel-medium |
Tier 1 surfaces (toolbars, headers, cards) |
--aurora-panel-strong |
Tier 2 surfaces (inspectors, primary content panels) |
--aurora-control-surface |
Input/control backgrounds |
--aurora-hover-bg |
Hovered rows, menu items |
Borders
| Token | Purpose |
|---|---|
--aurora-border-default |
Resting separators, dividers, table rules |
--aurora-border-strong |
Cards, inputs, selected surfaces |
Text
| Token | Purpose |
|---|---|
--aurora-text-primary |
Headings, body, control labels |
--aurora-text-muted |
Captions, meta, descriptions, placeholders |
Accents
| Family | Use for |
|---|---|
--aurora-accent-primary / -strong / -deep / -lift / -button (cyan) |
Primary CTAs, selection, focus, active state |
--aurora-accent-pink / -strong / -deep / -button (rose) |
Secondary CTAs, agent affordances, send buttons, key labels in mono code, active filter tags — one or two touch points per screen, not splattered |
--aurora-accent-violet / -strong / -deep / -button (violet) |
AI/automation identity — model selectors, reasoning panels, autonomous actions |
Each accent family has matching -surface and -border mix tokens; use those for tinted backgrounds and matching borders.
Status — muted, never neon
| Family | Tokens |
|---|---|
| info (cyan-lean) | --aurora-info, --aurora-info-surface, --aurora-info-border, --aurora-info-foreground |
| success (teal-mint) | --aurora-success, --aurora-success-surface, --aurora-success-border, --aurora-success-foreground |
| warn (warm sand) | --aurora-warn, --aurora-warn-surface, --aurora-warn-border, --aurora-warn-foreground |
| error (rose-clay) | --aurora-error, --aurora-error-surface, --aurora-error-border, --aurora-error-foreground |
| neutral (slate) | --aurora-neutral, --aurora-neutral-surface, --aurora-neutral-border, --aurora-neutral-foreground |
--aurora-status-offline is deprecated; alias to --aurora-neutral.
Radii, shadows, glows
--aurora-radius-1(14px) — chips, buttons--aurora-radius-2(18px) — small cards, popovers--aurora-radius-3(22px) — panels (Tier 1, Tier 2)- Tables override to
border-radius: 8pxon the wrapper (resolved decision) --aurora-shadow-mediumfor Tier 1,--aurora-shadow-strongfor Tier 2--aurora-highlight-medium/-strong— inset top highlights to pair with shadows--aurora-active-glow— border + glow for selected/active states--aurora-focus-ring/--aurora-focus-ring-strong— focus-visible rings
Typography ramp — semantic, not pixel-pushing
Use the .aurora-text-* classes from registry/aurora/styles/aurora.css. Pick the slot first; if the color is wrong, override color before inventing a new size.
| Class | Font | Use for |
|---|---|---|
.aurora-text-display-1 |
Manrope 800 | Page heroes, big numbers |
.aurora-text-display-2 |
Manrope 700 | Section heroes |
.aurora-text-section |
Manrope 760 | Section headers, card titles |
.aurora-text-body |
Inter 480, 14px | Default body |
.aurora-text-body-sm |
Inter 480, 13px | Compact body |
.aurora-text-ui |
Inter 560, 13px | Working UI text (controls, list items) |
.aurora-text-control |
Inter 560, 13px dense | Control labels, button text |
.aurora-text-table |
Inter 480, 13px | Table cells |
.aurora-text-label |
Inter 650, 12px | Form labels |
.aurora-text-caption |
Inter 560, 11px | Captions |
.aurora-text-meta |
Inter 560, 11px muted | Metadata, timestamps |
.aurora-text-eyebrow |
Inter 650, 11px uppercase | Eyebrows, badge labels |
.aurora-text-code |
JetBrains Mono 520 | Inline code, IDs, paths |
Mono is restricted. Use JetBrains Mono / .aurora-text-code only for code blocks, terminal output, file paths, IDs/hashes, badge chips in code contexts, and inline code snippets. Never for form labels, file tree names, body prose, general UI copy, or breadcrumb text.
Visual rules
- Three lift tiers. Tier 0 page is flat (the
.aurora-page-shellwash counts). Tier 1 toolbars/headers use--aurora-shadow-medium. Tier 2 inspectors/primary panels use--aurora-shadow-strong. Pair every elevated surface with an inset top highlight (e.g.inset 0 1px 0 rgba(255,255,255,0.05)). - Selection + focus = border + glow. Don't flood fills. Use
--aurora-active-glowfor selected items and--aurora-focus-ring/-strongfor keyboard focus. - Borders.
--aurora-border-defaultfor resting,--aurora-border-strongfor cards, inputs, selected surfaces. - No glassmorphism. No imagery on chrome. The only sanctioned chrome gradient is the
.aurora-page-shellwash. - Left-border glow (
border-left: 3px solid) for in-progress / active list indicators. Don't usebox-shadowfor left-edge indicators on rounded elements — it rounds the glow. - Stat cards are narrow tracks, not full-width:
grid-template-columns: repeat(auto-fill, minmax(175px, 220px)). - Tables use
border-radius: 8pxon the wrapper, not the 22px panel radius.
Components — use the registry, don't hand-roll
The full inventory with import paths lives in references/components.md. The categories:
- Foundations: tokens, type ramp, brand mark
- Controls: button, button group, badge, switch, avatar, progress, spinner, toolbar, kbd, separator, accordion, toggle, toggle group
- Form elements: field, label, input, input group, input OTP, select, native select, textarea, checkbox, radio group, slider, number input, combobox, date picker, tabs
- Feedback: alert/callout, banner, toast, tooltip, empty state, skeleton, shimmer
- Navigation: breadcrumb, sidebar, command palette, navigation menu, menubar, scroll area, pagination
- Data: stat card, card, item, table, data table, chart, carousel, filter bar, marketplace catalog, status indicator, timeline, description list, search results, calendar
- Overlays: dialog, alert dialog, dropdown menu, context menu, hover card, popover, sheet/drawer, collapsible, permissions dropdown, thinking disclosure
- Chat & AI blocks: prompt input, AI elements, message, inline citation, sources, suggestion, queue, checkpoint, confirmation, context, conversation, model selector, tool calls, reasoning, code block, artifact, terminal, permission prompt, ask-user-question, attachment, agent, commit, package info, sandbox, schema display, snippet, stack trace, test results, env vars
- Workspace blocks: file picker, file tree, code editor, JSX preview, web preview, share dialog, resizable panels
- Auth & errors: login, OAuth flow, error pages
Rule: if a registry component covers the affordance, import it. Don't hand-roll a <button> next to an Aurora Button. Don't hand-roll a status pill next to Badge.
Button — canonical example
import { Button } from "@/registry/aurora/ui/button"
<Button variant="aurora">Run query</Button> {/* primary cyan glow */}
<Button variant="rose">Send to agent</Button> {/* agent / send affordance */}
<Button variant="neutral">Cancel</Button> {/* secondary control */}
<Button variant="ghost">Filter</Button> {/* tertiary, no chrome */}
<Button variant="destructive">Delete</Button> {/* destructive action */}
<Button variant="aurora" size="sm">…</Button> {/* sm | default | lg | icon */}
The canonical button style is Aurora glow border — the component implements the gradient + inset highlight + cyan glow automatically. Hand-rolling that style is a smell.
Badge — Style B is canonical
import { Badge } from "@/registry/aurora/ui/badge"
<Badge tone="info">Pending</Badge>
<Badge tone="success">Online</Badge>
<Badge tone="warn">Degraded</Badge>
<Badge tone="error">Failed</Badge>
<Badge tone="rose">Filtered</Badge> {/* active filter tags */}
<Badge tone="violet">AI</Badge> {/* AI / autonomous */}
<Badge tone="neutral">Idle</Badge>
Style B is the canonical badge: square chip, JetBrains Mono, 4px radius, optional glow dot in currentColor. Pill styles (Style A, C, D) exist but are secondary — only reach for them when the surface specifically needs the lower-noise read.
Banner
Style A1 (elevated + glowing dot + dismiss) for high-priority alerts (error, warn, info). Style C (mono tag + single line) for inline table rows and compact notices. Style B (left rule) was explored and removed — don't reintroduce it.
Content rules
- Sentence case for buttons, headers, table columns, menu items. Active gateways, not Active Gateways.
- Uppercase only for eyebrows and badge labels.
- No exclamation marks in chrome.
- No "we", no apology framing, no marketing verbs.
- Status copy is matter-of-fact: "Backend unavailable.", "Plex authorized.", "Couldn't reach gateway. Retrying." — not "Oops! Something went wrong".
Designing a new surface — recipe
- Apply
className="aurora-page-shell"to the page root when the surface owns the page background. - For sidebars/nav rails, apply
className="aurora-nav-shell". - Build working areas on Tier 2 panels:
<div className="rounded-[var(--aurora-radius-3)]" style={{ background: "var(--aurora-panel-strong)", borderColor: "var(--aurora-border-strong)", borderWidth: 1, boxShadow: "var(--aurora-shadow-strong), inset 0 1px 0 rgba(255,255,255,0.05)", }} /> - Headers/toolbars sit on Tier 1:
background: var(--aurora-panel-medium),boxShadow: var(--aurora-shadow-medium). - Type: pick from the
.aurora-text-*ramp. Manrope for display/section titles, Inter everywhere else, mono only for code/paths/IDs. - Use tokenized tint fills:
color-mix(in srgb, var(--aurora-accent-primary) 14%, transparent). - Selection: border + glow (
--aurora-active-glow). Focus-visible:--aurora-focus-ring-strong. - Use registry components (
Button,Badge,Banner,StatCard,DataTable, etc.) before hand-rolling. - Verify the same surface renders correctly in
.lightbefore shipping.
See references/recipes.md for full copy-pasteable patterns: two-pane operator layout, command palette trigger row, stat grid, status row with badge + meta, agent prompt with model selector, data table with filter bar.
Resolved decisions — don't relitigate
These have been argued and settled. If you find yourself proposing the rejected option, re-read this list:
- Terminal chrome: Aurora-native only. No macOS circles/dots. Title bar uses
--aurora-panel-strong, the stacked-plane mark when available, and AuroraButtonactions for kill/clear/run. - Left-border glow:
border-left: 3px solidfor active/in-progress. Avoidbox-shadowfor left-edge on rounded elements (rounds the glow). - Breadcrumb badge position: Badge goes left of the item name.
- Stat cards: narrow tracks (
repeat(auto-fill, minmax(175px, 220px))), do not stretch full-width. - Table radii: 8px wrapper, not 22px panel radius.
- Active filter tags: rose. Cyan blends into the control surface.
- Toasts: Labby stacked-plane mark replaces colored dot/circle icons where the mark is available. Dismiss
xis colored by status type. - Banner Style B (left rule): removed. Use A1 or C.
Brand & mark
- Primary mark — stacked plane. Four isometric diamond planes (dark → light cyan, bottom → top) for cli / api / mcp / web layers. Canonical favicon, app icon, and inline mark when available.
- Secondary mark — hub & spoke. Six nodes radiating from a central core. Use only when the control plane fanning out to services read is needed.
- Wordmark —
Labby. Manrope 800, tight tracking, sentence case. The gallery rendersLabbin primary text and accentsywith--aurora-accent-pink. Verifyapp/gallery/demos/brand-demo.tsxbefore changing the canonical mark.
Registry workflow (only when working in the source repo)
When you've changed registry source:
- Inspect / update
registry.json. Token-dependent components must declareregistryDependencies: ["aurora-tokens"]. - Run
pnpm registry:build. This regeneratespublic/r/*.jsonandpublic/r/registry.json. They are otherwise stale. - If you added a gallery demo, wire both
app/gallery/[section]/page.tsxandapp/gallery/layout.tsx. - Run
pnpm lint. For route/demo changes, runpnpm buildto catch SSR/static-param breakage. - Verify inventory claims against
registry.jsonand gallery routes — don't write counts from memory.
Install URL for end users: https://aurora.tootie.tv (root) or https://aurora.tootie.tv/r/<name>.json (direct).
Reference files
references/tokens.md— full token list with values for both dark and light modes, plus the shadcn token bridge.references/editor-cli-tokens.md— non-web palettes: Zed "Aurora Neon", Claude Code CLI, shell tools, and the terminal ANSI foundation. Read this before touchingeditors/orshell/themes — it maps the three diverging cyan/rose tiers so you don't cross-contaminate.references/components.md— every UI primitive and block with import path and the props that matter.references/recipes.md— copy-pasteable patterns: page shell, two-pane layout, stat grid, command palette trigger, prompt input with model selector, data table with filter bar.
Read the reference that matches what you're about to build before you write the JSX.