// blake_petersen

Artax Design System

Terminal-inspired design system — theme tokens, typography, component conventions, and the aesthetic rules that define the UI.

artax-uitailwindcssdesign-systemtailwindcsscomponentsthemeterminal-aesthetic

3 min read · New · 👍 0

The Artax design system powers all UI across the petersen-group monorepo. It lives in packages/artax-ui and implements a terminal/CLI-inspired aesthetic: monospace typography, zero border-radius, amber accent, and dark backgrounds. Every component follows these conventions.

#// Aesthetic Principles

Terminal-first. The UI should feel like a well-designed terminal application, not a web app with a dark theme bolted on. This means:

  • Monospace font everywhere except long-form prose
  • Square corners on everything — no border-radius, ever
  • Single accent color (amber) for interactive elements
  • Minimal decoration — let content and type create hierarchy
  • Borders are functional (separation), not decorative (embellishment)

Component personality. Buttons prefix with $ in default variant and wrap with [ ] brackets in ghost variant, like terminal prompts and commands. This is subtle but reinforces the aesthetic throughout the interface.

#// Theme Tokens

All tokens are defined as CSS custom properties in packages/artax-ui/src/styles/theme.css using Tailwind v4's @theme directive. The token names map directly to Tailwind utility classes.

#> Colors — Dark Mode (default)

TokenValueUsage
--background#0A0A0APage background
--foreground#FAFAFAPrimary text
--card#0F0F0FCard/panel backgrounds
--card-foreground#FAFAFACard text
--popover#0F0F0FPopover/dropdown backgrounds
--primary#F59E0BInteractive elements, links, focus rings
--primary-foreground#0A0A0AText on primary backgrounds
--secondary#1F1F1FSecondary backgrounds
--secondary-foreground#FAFAFASecondary text
--muted#1F1F1FMuted backgrounds
--muted-foreground#6B7280Muted/placeholder text
--accent#1F1F1FAccent backgrounds
--accent-foreground#FAFAFAAccent text
--border#2A2A2ABorders and dividers
--input#2A2A2AInput borders
--ring#F59E0BFocus rings
--destructive#EF4444Destructive actions
--success#10B981Success states
--info#06B6D4Info states
--warning#F59E0BWarning states (same as primary)

#> Colors — Light Mode

TokenValueUsage
--background#F5F5F5Page background
--foreground#171717Primary text
--primary#D97706Amber, slightly darker for contrast
--card#EBEBEBCard backgrounds
--border#D4D4D4Borders
--muted-foreground#737373Muted text

#> Surface Colors

Semi-transparent backgrounds for status banners and badges:

TokenDarkLight
--surface-inforgba(6, 182, 212, 0.06)rgba(8, 145, 178, 0.08)
--surface-warningrgba(245, 158, 11, 0.06)rgba(217, 119, 6, 0.08)
--surface-successrgba(16, 185, 129, 0.06)rgba(5, 150, 105, 0.08)

#> Border Radius

All zero. No exceptions.

--radius: 0px;
--radius-sm: 0px;
--radius-md: 0px;
--radius-lg: 0px;
--radius-xl: 0px;

#// Typography

Three font families, loaded via CSS custom properties:

PropertyFontUsage
--font-monoJetBrains MonoPrimary — UI text, labels, navigation, buttons
--font-mono-altIBM Plex MonoAlternative mono — code blocks, technical content
--font-sansInterLong-form prose only (blog posts, documentation body)

All components default to font-mono. The font-sans class is explicitly applied only in article/prose contexts.

#// Type-Safe Token Access

The tokens.ts module in packages/artax-ui/src/styles/ exports typed constants for programmatic access:

import { tokens } from '@petersen-group/artax-ui/styles/tokens'

tokens.bg.background    // 'var(--background)'
tokens.text.primary     // 'var(--primary)'
tokens.border.border    // 'var(--border)'
tokens.font.mono        // 'var(--font-mono)'

Organized by namespace: bg, text, border, ring, font. Use these in inline styles or dynamic class generation instead of hardcoding CSS variable names.

#// Component Conventions

Components live in packages/artax-ui/src/components/ organized by atomic design:

components/
├── atoms/       # Badge, Button, Input, etc.
├── molecules/   # SearchInput, NavItem, etc.
└── organisms/   # Header, Sidebar, etc.

#> Required Patterns

Every component file follows these conventions:

  1. ABOUTME comment at the top — two lines describing what the file does
  2. cva for variants — all variant logic uses class-variance-authority
  3. cn() for class merging — never concatenate class strings manually
  4. Export both component and variants — consumers may need the variants object for composition
  5. font-mono by default — all components use monospace unless explicitly overridden
  6. Focus statesfocus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring
  7. Disabled statesdisabled:pointer-events-none disabled:opacity-50

#> Example: Button Personality

// Default variant: terminal prompt style
<Button>deploy</Button>        // renders: "$ deploy"

// Ghost variant: command bracket style
<Button variant="ghost">help</Button>  // renders: "[ help ]"

The $ prefix and [ ] brackets are added via the variant definitions in cva, not as children. This keeps the terminal personality consistent without requiring every consumer to remember the convention.

#// CSS Architecture

Tailwind v4 with PostCSS plugin (no tailwind.config.js). All customization via CSS custom properties:

  • packages/artax-ui/src/styles/theme.css — token definitions under @theme
  • packages/artax-ui/src/styles/globals.css — imports Tailwind, theme, animations
  • apps/blakepetersen.io/src/app/globals.css — imports artax-ui globals, sources component files

Theme switching uses [data-theme=dark] selector on the root element, not a class="dark" approach.

// decisions

Zero border-radius on all components

The terminal aesthetic demands sharp edges. Rounded corners signal consumer software; square corners signal developer tooling. Every radius variable is explicitly set to 0px.

Amber as the sole accent color

Single-accent constraint forces hierarchy through typography and spacing rather than color variation. Amber reads as warm-terminal without being as aggressive as green-on-black.

JetBrains Mono as primary font, Inter as fallback sans

Monospace-first reinforces the terminal aesthetic. JetBrains Mono has excellent readability at small sizes and distinctive ligatures. Inter is only used where monospace would look wrong (long-form prose).

Dark mode as default, light mode as alternative

The terminal aesthetic is inherently dark. Light mode exists for accessibility and outdoor use but is not the design target.

Use cva (class-variance-authority) for all component variants

cva provides type-safe variant definitions that compile to Tailwind classes. Eliminates the ternary soup that variant logic usually becomes.