# Tidal Design System — full documentation A shadcn-style component library and design token system, sourced from Figma. Lilac brand, Söhne family, light + dark modes. --- # Introduction Tidal is a shadcn-style React component library and design token system sourced from Figma. - **Brand:** Lilac `#cd82f0` - **Fonts:** Inter (sans, internal) / Söhne (sans, external), Georgia (serif / external headings), JetBrains Mono (mono) - **Modes:** Light + Dark, toggled via `class="dark"` on `` - **Tokens:** Exported from Figma in DTCG format to `/design-tokens/`, imported by `packages/tokens/scripts/build.ts`, emitted as CSS vars + Tailwind preset + JSON. Agents: read `DESIGN.md` in the repo root before modifying anything. --- # Installation ```bash pnpm install pnpm tokens:build pnpm dev ``` Docs site runs at http://localhost:3000. --- # Using with AI agents How to point an AI coding agent at Tidal docs — without cloning the repo. ## If you have the repo Three files in the repo root are mandatory reading: - `AGENTS.md` — decision tables for which component to use, plus a forwarded summary of DESIGN.md §0–§8. Claude Code reads this automatically on startup. - `DESIGN.md` — the full design rubric: token taxonomy, forbidden patterns, composition rules, and the §10 pre-build checklist. Required before writing any UI code. - `ux_patterns_researched.md` — researched layout patterns and UX decisions. Reference when making structural layout choices. **Claude Code:** `AGENTS.md` is auto-read on startup. No extra steps. **Cursor / other agents:** Paste the contents of `DESIGN.md` into your agent context, or add a `.cursorrules` file that fetches it (see below). ## Remote usage (no clone needed) The docs site exposes machine-readable endpoints: - `/llms-full.txt` — all component docs + DESIGN.md + FIGMA_SYNC.md in one file. Best single-URL context for agents. - `/llms.txt` — manifest of every doc page with one-line descriptions. Use this to let the agent fetch individual pages selectively. - `/design.md` — DESIGN.md alone: token taxonomy, forbidden patterns, composition rules. Add this to your agent's system prompt: ``` Read https://tidal-design-system-docs.vercel.app/llms-full.txt before building any UI with Tidal components. ``` ## Add to your project for agent access Drop one of these files in your project root so agents pick up Tidal context automatically. ### CLAUDE.md ```markdown # UI — Tidal Design System This project uses the Tidal Design System for all UI. Before building any UI: 1. Read https://tidal-design-system-docs.vercel.app/llms-full.txt — all component docs and design rules. 2. Never inline hex colors. Always use Tidal semantic tokens (CSS vars or Tailwind utilities). 3. Never write `dark:` variants in components — fix the token if a dark variant is missing. 4. Default to the calmest variant. Escalate only with intent. 5. If the brief is underspecified, ask for clarity before writing code. ``` ### .cursorrules ``` # Tidal Design System Read https://tidal-design-system-docs.vercel.app/llms-full.txt before writing any UI code. Rules: - Use @tidal-ds/react components. Don't hand-build what the library already ships. - Use semantic token CSS vars (e.g. var(--primary)) or Tailwind utilities. No raw hex. - Follow the variant x tone API shape. One Primary action per page. - No dark: in component classes. Token-level fix only. - Ask for clarity before building underspecified screens (see DESIGN.md §10). ``` ## Prompt templates ### Build a new page ``` Build a [page type] page using the Tidal design system. Context: - Read https://tidal-design-system-docs.vercel.app/llms-full.txt first. - Data: [describe the data shown] - States: [loading / empty / error / populated] - Actions: [primary action, secondary actions, destructive actions if any] - Layout: [sidebar + main / full-width / two-column / etc.] Follow DESIGN.md §10: if anything is underspecified, ask before writing code. ``` ### Add a feature to an existing page ``` Add [feature] to [page/component]. Context: - Read https://tidal-design-system-docs.vercel.app/llms-full.txt first. - Existing components in scope: [list relevant components already on the page] - New components needed: [your best guess — the agent should verify against /llms.txt] - Interaction: [how the feature is triggered, what it controls, any states] Don't invent new components if Tidal already ships one that fits. ``` Per DESIGN.md §10: an agent should ask for clarity when a brief is underspecified — not silently fill in gaps. --- # Color tokens Semantic color tokens — light + dark values for every surface. Reference via CSS vars (e.g. `var(--primary)`) or Tailwind utilities, never raw hex. Groups: `background`, `foreground`, `card`, `popover`, `border`, `input`, `accent`, `ring`, `button` (primary/default/destructive/success), `sidebar` (8 tokens), `neon-green`. Faded surfaces: `--background-destructive-fill-10` / `--background-destructive-hover-20` (and `-success-` equivalents) for callouts and low-emphasis destructive backgrounds. Liquid (brand) palette: Lilac, Viola, Mandarin — each with alpha variants (10/30/50/70/Full) and Lilac has a `Darker` step. Source of truth: `/design-tokens/Semantics.{light,dark}/liquid.tokens.json`. --- # Typography - **Families** (mode-aware): - `font-sans` = **Inter** (Internal) / **Söhne** (External). Resolved via `var(--font-sans)`. - `font-serif` = **Georgia** (system font). - `font-mono` = **JetBrains Mono**. - `font-heading` = `var(--font-sans)` in Internal, `Georgia` in External. Use on page headings and display text. - **Heading weight**: `--font-heading-weight` is `600` (semibold) in Internal, `400` (normal) in External. - **Weights (Söhne files shipped)**: Leicht (300), Buch (400), Kräftig (500). `font-semibold` (600) falls back to Kräftig. - **Two size scales** switched by parent class: - **Internal** (default, `:root` / `.typography-internal`): compact app scale, Inter sans. `text-base` = 14. Use for internal apps and ML tools. - **External** (`.typography-external`): larger scale, Söhne sans, Georgia headings. `text-base` = 16. Use for marketing sites, landing pages, public-facing docs. The utility `text-base` resolves to `var(--text-base)` so components don't need to switch classes between modes. ## Text styles Canonical pairings of size × leading × weight × font. Use these together — don't pair `text-base` with a different `leading-*` ad-hoc. If a use case needs a different combo, propose a new style here. Sizes shown as **Internal / External** in pixels. | Use | Class | Size (int / ext) | Font | When to use | |---|---|---|---|---| | **Body (default)** | `text-base leading-6 font-normal` | 14 / 20 | sans | Default for paragraphs, list items, prose. | | **Emphasis paragraph** | `text-base leading-6 font-medium` | 14 / 20 | sans | Bump a single paragraph or sentence that needs to stand out within prose. Don't use for titles. | | **Description / secondary** | `text-base leading-6 font-normal text-muted-foreground` | 14 / 20 | sans | Field descriptions, captions under content, muted metadata. Same size as body, tonally quieter. | | **Caption / metadata** | `text-xs leading-4 font-normal` | 11 / 16 | sans | Tiny labels, timestamps, badge text. | | **Subhead** | `text-lg leading-7 font-medium` | 16 / 24 | sans | Subsection headers within a card or section. | | **Section heading** | `text-xl leading-7 font-medium tracking-tight` | 18 / 24 | sans | Top of a page section. | | **Page heading** | `text-3xl leading-9 font-semibold tracking-tight` | 28 / 36 | sans · serif (ext) | Page title (PageHeader). Uses `font-heading` + `--font-heading-weight`. | | **Display** | `text-5xl leading-none font-semibold tracking-tight` | 48 / 48 | sans · serif (ext) | Marketing hero copy. Uses `font-heading` + `--font-heading-weight`. Sparingly. | | **Code** | `text-sm leading-5 font-mono` | 12 / 18 | mono | Inline code references, prop names, file paths. | Non-code samples render in `font-sans` (Inter or Söhne depending on mode); code samples render in `font-mono` (JetBrains Mono). Set fonts explicitly rather than relying on inheritance so styles don't drift if a parent changes font. --- # Spacing, radius, shadows - **Spacing**: 4px-aligned, from `spacing-0` (0) to `spacing-8` (32). Tailwind primitives. - **Radius**: `--radius` = 10px (base). `rounded-sm` = 6, `rounded-md` = 8, `rounded-lg` = 12, `rounded-xl` = 16, `rounded-full`. - **Shadows**: `shadow-sm`, `shadow`, `shadow-md`, `shadow-lg`, `shadow-xl`, `shadow-2xl`, `shadow-inner`, `shadow-input-inner` (mode-aware: 6% light / 10% dark). --- # Gradients & focus rings Buttons use gradients, not flat fills. - **Primary** (Lilac): horizontal lilac base (`#dc92ff → #9d82f0` @ 306°) + subtle vertical darken overlay. Hover swaps the lilac stops for viola tones (`#964aba → #6666bf`). - **Default / Destructive / Success**: vertical fill → hover. - Hover cross-fades via a `::before` pseudo with `opacity` transition (150ms ease-out) — CSS can't animate between gradients, so we overlay. Utilities: `bg-button-{primary, primary-hover, default, default-hover, destructive, destructive-hover, success, success-hover}`. Focus rings are compound box-shadow tokens (not outlines): - `shadow-ring-primary`: 1px lilac + 1px halo - `shadow-ring-destructive`: 2px background spacer + 2px destructive ring - `shadow-ring-primary-input` / `-destructive-input`: stacked with `--shadow-input-inner` so focused inputs keep their depth. Apply via `focus-visible:shadow-ring-primary focus-visible:outline-none focus-visible:border-focus`. --- # Button ## Usage — reserve Accent for one CTA per page **Primary** (high-contrast inverse — dark in light mode, light in dark mode) is the workhorse CTA. **Accent** (lilac, via `tone="accent"`) is the brand moment — reserved for the single most important action on a view. Aim for **at most one** Accent button per page. If you're reaching for multiple Accent buttons, first ask: can they all be `variant="primary"` (default tone)? If one genuinely outranks the others, keep that one on `tone="accent"` and demote the rest. Agents implementing designs should flag this back to the user when they see more than one Accent. ```tsx import { Button } from "@tidal-ds/react"; ``` ## Props | Prop | Type | Default | |---|---|---| | `variant` | `"primary" | "default" | "outline" | "ghost" | "link"` | `"primary"` | | `tone` | `"default" | "destructive" | "success"` | `"default"` | | `size` | `"sm" | "md" | "lg"` | `"md"` | | `loading` | `boolean` | `false` | | `disabled` | `boolean` | `false` | | `iconLeading` | `ReactNode` | — | | `iconTrailing` | `ReactNode` | — | | `asChild` | `boolean` (Radix Slot) | `false` | ## Notes - Icon color defaults to `muted-foreground`. The three "filled" variants (`variant=primary` with tones default/destructive/success) have white text and white icons. - `disabled` or `loading` sets inline `opacity: 0.5` (immune to class-merge quirks). - Primary variants use a `::before` overlay for smooth gradient cross-fade on hover. Source: `packages/react/src/components/button.tsx`. Figma node `2718:8237`. --- # IconButton Square button with a single icon. Shares `variant` and `tone` with `