Design principles
The rules Veritheme is built on — and the same rules its MCP server enforces when AI generates UI with it.
One rulebook for humans and AI
These principles govern every Veritheme surface: the components themselves, the docs and examples, the Figma library — and AI output through the MCP server, which carries them as generation rules.
AI-ready by design
Connect npx -y @veritheme/mcp-server and generated UI follows this page automatically — component choice, type scale, spacing grid, color roles, composition patterns.
The principles
Hard rules are enforced (build guards on this site, generation rules in MCP). Soft ones are followed for polish.
Semantic-first
GuidelineThe token and class names are the design intent — match the meaning of the content to the name instead of picking by how something looks. success = positive/confirmation, warning = caution, error/danger = failure or destructive, info = neutral notice and focus, accents-brand = the product’s own accent. mains steps primary → quaternary from most to least important; surfaces name elevation; typography classes name role. The rules below are the guardrails; choosing the semantically-correct token is the goal.
Component-first
RuleIf a component exists for the element, use its classes — never rebuild it from utilities, and never override a component’s size or colors with utilities (pick the proper variant instead). Utilities are for layout only: flex, grid, gap, spacing, max-width.
Minimum text size is 12px
RuleNothing renders below the xs token (12px) — even Overline is 12px; there is no 11px in the scale. At 12px, prefer the semantic class over a raw size: vt-caption for fine print, vt-text-overline for uppercase eyebrows, vt-section-label for group labels.
Spacing lives on the grid
RulePaddings, margins, gaps and sizes come from the spacing scale only. No arbitrary pixel values — if a step feels missing, snap to the nearest one. Rhythm: mt-8 between page sections, gap-4–6 between cards, gap-2–3 inside groups.
Color comes from tokens
RuleNo hex, no rgb, no inline styles. Interactive and accent elements use accents-brand; blue info-* is reserved for informational states and focus. Surfaces follow the hierarchy (background → surface → subtle → moderate) so dark mode works automatically. Text steps down mains-primary → secondary → tertiary → quaternary; intent colors only mean their state.
Radii from the scale — concentric when nested
GuidelineCorner radii come from the radius scale. When a rounded element sits inside a rounded container, prefer inner radius = parent radius − padding so the corners run parallel (vt-rounded-concentric-3 inside a p-3 card). An aesthetic guideline, not a law — skip it when it fights the layout.
Start from a proven composition
GuidelineFull screens start from a pattern, the way a designer starts from a known layout: content column max-w-5xl px-6 py-8, app header h-16, sidebar with section labels. The examples gallery is the pattern library — the MCP server serves the same skeletons to AI via list_patterns / get_pattern.
Design the states, not just the happy path
GuidelineEvery list, table and board gets an empty state (icon, one line, primary action). Loading is a skeleton shaped like the content. Long text truncates. Destructive actions confirm via dialog. One primary button per view.
Write like a product
GuidelineSentence case everywhere — buttons, labels, headings. No lorem ipsum: realistic names, dates, sizes and trends. Labels are one to three words. No exclamation marks.
Accessible by default
GuidelineFocus states stay. Icon-only controls carry an aria-label. Images get meaningful alt text. Text/surface pairs from the color hierarchy keep contrast at AA.
Common mistakes
The frequent failure modes — what the rules above exist to prevent.
Rebuilding a component from utility classes
A component almost always exists — use vt-badge, vt-btn, vt-avatar… Utilities are for layout only.
Overriding a component’s size or color with utilities
Pick the variant/size class (vt-btn-sm, vt-badge-soft) instead of vt-text-sm / vt-bg-* on the component.
Using blue info-* for primary actions or accents
Interactive and accent elements are accents-brand; info-* means informational state and focus only.
Intent colors as decoration (a blue heading, green divider)
success/warning/error/info carry meaning — use mains-* and surfaces-* for neutral UI.
Text below 12px, or arbitrary spacing / radius values
Everything comes from the scale: vt-text-xs and up, spacing steps, radius scale — no [13px].
Nesting a card inside a card
Divide card content with spacing or separators; page sections are spacing-separated, not boxes-in-boxes.
Hardcoded white / grey backgrounds
Use the surface hierarchy (surfaces-background → surface → subtle → moderate) so dark mode just works.
Icon-only buttons with no label, or removed focus rings
Every icon-only control gets a title/aria-label; never remove focus-visible styling.
More than one primary button per view
One vt-btn-primary; secondary actions use bordered or ghost.
A list, table or board with no empty state
Design the empty state (vt-empty-state) and the loading state (vt-skeleton) too, not just the happy path.