Building UI with the Visualli design system
Read this before writing or refactoring any frontend code in this monorepo (web app, www, MCP apps, Chrome extensions). It is the contract: build from these components and tokens only. CLAUDE.md in this folder is for changing the design system itself.
Sources of truth — read in this order
components/dist/index.d.ts— every component and its props. If it isn't exported here, it isn't in the system.components/catalog/<Name>/README.md— when to use each component, and its do's and don'ts.tokens/tokens.json— every token, with ausagenote saying where it belongs. Generated forms:tokens/dist/tokens.css(CSS variables),tokens/dist/tailwind.preset.cjs(Tailwind),tokens/dist/tokens.ts(typed object).docs/guidelines/brand-book.md(voice, color roles, type roles),canvas-language.md(maps, nodes, gestures),surfaces.md(page layouts),comfort-modes.md(themes and accessibility).- The built docs site (
npm run build→docs/dist/) has a live gallery with copyable JSX for every core component, andllms.txtlists every page as Markdown.
Setup in an app
import '@visualli/design-system/tokens.css'; // once, at the app root
import '@visualli/design-system/bundle.css'; // once, after tokens.css
import { Button, Card, TextField, Dialog } from '@visualli/design-system/components';
Tailwind (3.4) — use the preset so only token values have classes:
// tailwind.config.js — new app
module.exports = { presets: [require('@visualli/design-system/tailwind-preset')], content: ['./src/**/*.{ts,tsx,html}'] };
// existing app while migrating: theme: { extend: require('@visualli/design-system/tailwind-preset').theme }
Set the theme on <html>: data-theme = light | dark | focus-light | focus-dark | colorsafe-light | colorsafe-dark | contrast-light | contrast-dark, plus data-type, data-motion, data-reveal, data-scale — or call applyComfort(choice) from ComfortPanel. Never branch on dark mode in component code; the variables switch.
Rules
- Components first. Use a system component whenever one fits. Common names map like this:
You want Use Button, link button, CTA Button(variant:primary,secondary= outline,ghost,danger;size:sm,md,lg)Icon-only button IconButton(always passlabel)Input, InputField, textarea TextField(multilinefor textarea)Search box SearchFieldToggle, checkbox-like setting SwitchTabs / radio group (2–4 options) SegmentedControlModal, dialog, confirm DialogCard, tile, panel section CardDropdown / context menu MenuSnackbar, notification ToastTag, chip, status pill BadgeTooltip TooltipIcon Iconwith a Lucide name fromICONSLoader / spinner ThinkingTree(map work) orButton loadingChat input Composer; messages:ChatTurnSidebar list of maps Vault/VaultItemMap / mind map / canvas VisualMap(never draw nodes by hand;Node,Edge,SemanticPeek,DepthTrailfor custom canvases)Read-only .visualliviewer (desktop viewer, third-party embeds)VisualliViewerfrom@visualli/design-system/spec— the spec layer only; never add product features to itHover card / summary popover for an idea SemanticPeekDefinition popover for a word, glossary term SemanticAnchorExplainer side panel / "learn about X" GoDeeper(facets + Map it)Attachments / uploaded files / "view source" for a map SourcesPanel(viaVisualMapaside)Chrome extension side panel / "visualize this page" ExtensionPanel(inchrome.sidePanel; no own brand or ✕ there)Floating button group .vi-toolbarwithButton/IconButton(size="sm")Editing a map: toolbar, contextual actions, inline rename VisualMapediting/onEdit(rendersEditBanner,SelectionBar,InlineText,SummaryEditor);applyEditon the serverFile / link attachment SourceChipSettings for theme / accessibility ComfortPanel - Tokens only for everything else. Layout and spacing between components use tokens:
var(--space-4),var(--radius-md),var(--surface)— or the preset's classes (p-4,gap-3,rounded-md,bg-surface,text-ink,shadow-float,font-ui,text-body). No hex/rgb values, no px values off the spacing scale, no other fonts, no ad-hoc shadows, durations or easings. If a token is missing, stop and ask; don't invent one. - Don't restyle components. No overriding
vi-*classes or passing style props to change their look. If a variant is missing, propose it for the design system instead of forking it in the app. - Accessibility is part of done. Text on the grounds its token note names (4.5:1; 7:1 in
contrast-*), visible focus (the components handle it; custom elements useoutline: 2px solid var(--focus)), labels on every control, touch targets ≥ 44px, motion that degrades underdata-motion="reduced"/prefers-reduced-motion. Never encode meaning in color alone. - Brand rules that are easy to break: no gradients (the spectrum appears as whole adjacent colors:
SpectrumBar); hand faces (font-hand,font-note) only on the canvas and in marketing, never in controls; Haksen (font-display) is caps-only; oneSignatureword per screen; no colored side borders on cards; no emoji in product chrome. - Copy: sentence case, American spelling, the vocabulary in the brand book — Visualli / Visuallis, vault, idea (node in code), connector, layer, rings, peek, step inside (enter an idea's layer), go deeper (understand it), map it, bring.
- Logos and icons come from
assets/andICONS; never redraw, recolor or substitute them. - Check before you finish: run the app in
lightanddark(and one comfort palette), at phone, tablet and desktop widths; no horizontal scroll; no console errors.
Prompt to give a coding agent
Build the new ‹page› using ONLY the components and tokens of our design system. Read
design-system/AGENTS.mdfirst and follow it: components from@visualli/design-system/components(API indesign-system/components/dist/index.d.ts), every other value fromdesign-system/tokens/tokens.jsonvia CSS variables or the Tailwind preset. Don't hard-code colors, sizes, fonts, shadows or motion, and don't restyle components. If something you need doesn't exist, stop and list it as a proposed addition instead of inventing it. Verify in light and dark, and at phone, tablet and desktop widths.
