# 03 · Theme and brand

A theme isn't a color — it's a **system of chained decisions**. In Fayz you declare three decisions in `app.manifest.json` and the shell's theme engine derives the entire palette from them. The shell stays the same; only the look changes, and it changes coherently.

## Step 1 · Think in systems

Before editing, pick three things — each one cascades through dozens of tokens:

- **Brand color** → becomes `primary`, the focus ring, a derived `accent` and (optionally) the colored sidebar.
- **Corner personality** (the radius) → sets buttons, cards, inputs and modals all at once.
- **Mode strategy** → light, dark, or follow the operating system.

Three decisions, not thirty colors. That's the whole point of a Design System.

## Step 2 · Apply it in the manifest

Freshly created, the app ships with `"theme": { "brand": "violet" }`. The block accepts three keys:

```json
{
  "theme": {
    "brand": "teal",
    "radius": "lg",
    "mode": "system"
  }
}
```

Looks like very little — and that's on purpose. Each key is the root of a chain. Here's what it unfolds into.

### Gallery of the 7 brands

Choosing `brand` means choosing a whole family. The engine takes the brand's hue, applies it to `primary`/`ring` and rotates the hue **−50°** to generate a harmonic `accent` automatically. The table below shows, per brand, the base hue, the derived `accent` and where each one shines:

| Brand | Base hue (HSL) | Becomes `primary`/`ring` | Derived `accent` (hue −50°) | Personality · when to use |
| --- | --- | --- | --- | --- |
| `blue` | `221 83% 53%` | institutional blue | `171` → green-cyan | Trust, corporate. B2B SaaS, fintech, legal. |
| `violet` | `262 83% 58%` | premium violet | `212` → blue | Neutral-premium, creative, tech. The scaffold default. |
| `green` | `142 71% 45%` | vivid green | `92` → lime | Care and growth. Health, finance, sustainability. |
| `orange` | `25 95% 53%` | warm orange | `335` → pink | Appetite and energy. Food, hospitality, retail. |
| `red` | `0 84% 60%` | strong red | `310` → magenta | Urgency and passion. Sports, delivery, promotions (careful: it lives next to `destructive`). |
| `pink` | `330 81% 60%` | vibrant pink | `280` → violet | Lifestyle and expression. Beauty, fashion, young D2C. |
| `teal` | `172 66% 50%` | aqua green | `122` → green | Calm and clarity. Clinics, wellness, productivity apps. |

{% callout type="info" %}
The HSL values above are **representative** — they're there so you can reason about each family and the `accent` that comes out of it. The platform runtime applies the calibrated variant of each name. The derivation rule (hue −50°, same saturation and lightness) is the same; what changes is the exact starting point.
{% /callout %}

### What each key cascades into

| Key | Value | What changes at once |
| --- | --- | --- |
| `brand` | one of the 7 names | `primary`, `ring`, `accent` (hue −50°) and, if you opt in, the colored sidebar — all from the same root. |
| `radius` | `none` | Square corners — a **technical, dense** read (tables, back office). |
| | `sm` | Subtle rounding — **sober**, corporate. |
| | `md` | The **balanced** middle ground — the safe pick. |
| | `lg` | Generous corners — **friendly**, tactile to the touch. |
| | `full` | Pills and circles — **playful**, consumer. |
| `mode` | `system` | Respects the user's OS — the sensible default. |
| | `dark` | Always dark — night apps, backstage, a floor plan at night. |
| | `light` | Always light — daytime operation, reception, front desk. |

Notice that `radius` doesn't change "the button": it changes **buttons, cards, inputs and modals** together, in the same proportion. That's what keeps the app coherent when you change one end of it.

### 3 ready-made recipes

Copy, paste into `app.manifest.json` and adjust the `name`. Each is a tested combination of brand + radius + mode for a type of business:

**Clinic / health**

```json
{
  "theme": { "brand": "green", "radius": "md", "mode": "light" }
}
```

Green communicates care and trust; `md` balances formal and approachable; `light` suits a reception desk and daytime service.

**Food / evening orders**

```json
{
  "theme": { "brand": "orange", "radius": "lg", "mode": "dark" }
}
```

Orange is appetite and hospitality; `lg` makes the targets tactile for quick taps; `dark` rests the eyes on the floor at night.

**Sober B2B SaaS**

```json
{
  "theme": { "brand": "blue", "radius": "sm", "mode": "system" }
}
```

Institutional blue reads as safe; `sm` keeps the professional density; `system` respects the operator's OS throughout the day.

The `name` at the top of the manifest is the display name — change it along with the color so the rebrand is complete:

```json
{
  "name": "My Clinic",
  "theme": { "brand": "green", "radius": "md", "mode": "light" }
}
```

## Step 3 · Validate

Edit the block, save, and run doctor:

```bash
npx @fayz-ai/cli doctor
```

```
⚠ plugins referenced by manifest are resolved by the platform bundle, not public npm packages: dashboard

0 error(s), 1 warning(s)
```

{% callout type="tip" %}
✓ You should see: `0 error(s)` from doctor. The warning about plugins resolved by the platform bundle is expected in mock mode — it isn't an error. Doctor confirms the manifest is well-formed and sound before the platform consumes it.
{% /callout %}

## Under the hood

Those three keys are the **condensed expression** of a larger system. Starting from your brand color, the theme engine (`createTheme` / `applyTheme`, in `@fayz-ai/saas`) derives the chain — verified in the code:

| Derived token | Where it comes from |
| --- | --- |
| `primary` | the brand, with a white `primaryForeground` for contrast over the fill. |
| `ring` (focus) | the same brand — the ring inherits the identity. |
| `accent` | the brand hue rotated **−50°** (same saturation and lightness), a second harmonic tone. |
| sidebar (optional) | the rail background takes the brand, white text, border at **−12%** lightness, active item at **−15%**, secondary icons at `hue 35% 82%`. |
| neutrals, surfaces, semantics, radius, shadows, typography | from a **curated base preset** (the classic admin), into which your brand slots. |

`applyTheme` then writes every value as a **CSS variable** on the document (`--primary`, `--ring`, `--accent`, `--sidebar`, `--button-radius`, `--font-family`, `--shadow-sm/md/lg`). Your brand is **one input** into an already consistent token system.

{% callout type="info" %}
The derivation happens in the **Fayz platform runtime**, which consumes the `theme` block to paint the whole shell. In the local scaffold preview — today an anchor screen — the palette isn't applied yet. That's why this step is validated with `doctor` (valid config), while the full visual result shows up in the platform runtime.
{% /callout %}

Want the whole chain — the eight token families, the contrast reasoning and the flow of designing the system before configuring it? It's in the [Design System and theming](/en/docs/apps/theming) chapter.

See also: the [full token reference](/en/docs/reference/theme-tokens) — a quick lookup of the families and the CSS variables the engine writes.

## Beyond the 3 keys {% badge status="experimental" /%}

The manifest exposes three decisions today, but the engine underneath is far richer. Already sitting behind the platform runtime: **free-form HSL color** (not just the 7 names), **11 font families** (from `inter` and `geist` to `outfit` and `manrope`), **shadow levels** (`none` → `subtle` → `medium` → `bold`), the sidebar in `brand` or `neutral` mode, and entire base **presets**. Exposing those families in the manifest — without bloating it — is the next step for the theme contract; the direction is evolutionary, not finished.

{% callout type="tip" %}
Workflow tip: design the system as an **artifact** first. A design session with AI produces a `tokens.css` with the complete families (brand, tints, typography, elevation); the manifest's `theme` block becomes the **condensed expression** of that artifact, and you promote tokens into the [Customization](/en/docs/apps/customization) seams as you grow. The manifest declares the theme — it isn't where you discover it.
{% /callout %}

---

[← Previous: 02 · Explore the anatomy](/en/docs/tutorial/02-explore-the-anatomy) · [Next: 04 · Add a plugin →](/en/docs/tutorial/04-add-a-plugin)
