> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vibestrap.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Customization

> What buyers customize, where to change it, and what stays out of the way.

90% of customization happens in three files: `src/config/site.ts`,
`src/app/globals.css`, and `messages/{en,zh}.json`. The rest is swapping logo
SVGs, editing email templates, and re-composing marketing blocks. This page is
the map.

## Quick swaps via `siteConfig.ui`

Two pre-built switches you flip without writing a single line of CSS — they
exist because the underlying change is cross-cutting and easy to get wrong:

```ts theme={null}
ui: {
  theme: 'cream' as 'cream' | 'white' | 'ash',
  // cream  — warm editorial paper (default; Loops / Resend / Clerk feel)
  // white  — clinical pure white (Stripe / Linear / Vercel feel)
  // ash    — cool gray-blue, airy (Apple / Bolt feel)

  navStyle: 'underline-fade' as
    | 'tone'              // Stripe / Resend — color-only shift
    | 'underline-fade'    // Notion / Loops — underline fades in (default)
    | 'pill'              // Linear / Vercel — rounded background
    | 'underline-appears' // NYT — instant underline on hover
    | 'split',            // v0 — pill on hover, line on active
}
```

Theme classes live in `src/app/globals.css`; nav recipes live in
`src/components/layout/nav-styles.ts` (each preset documents the source
site it's modeled on). Add a new preset by extending the file — the
TypeScript union narrows automatically.

## Customize with AI

Vibestrap ships intentionally **few** pre-built presets. Most block-level
changes — the hero, pricing card, footer, button variant, card visual — are
faster for an AI agent to generate than for a preset system to maintain.

For the common ones, [`STYLES.md` → AI swap recipes](https://github.com/xiaohu0x/vibestrap/blob/main/STYLES.md#ai-swap-recipes--single-block-customization)
ships copy-paste prompt templates that name the exact files and constraints.
Open the recipe for the block you want to change, paste the prompt into Claude
Code / Cursor / Codex, and the change usually lands in 2–5 minutes.

Recipes available:

* Swap the **hero** (terminal demo → centered headline / split-screen / video bg)
* Restyle the **pricing card** (single → two-card monthly+yearly / 3-tier / slider)
* Swap the **feature-card** visual (hard-border → soft-shadow / glass / gradient)
* Compact the **footer** (4-col → minimal one-row / mega-with-newsletter)
* Restyle the **primary button** (solid → outlined / gradient / ghost)

For full re-skins (cream-mono → dark tech, etc.) see the seven complete style
recipes earlier in `STYLES.md` — same file, top of the document.

## Brand identity

Edit `src/config/site.ts` — the central config:

```ts theme={null}
export const siteConfig = {
  name: 'YourProduct',
  description: 'Your one-paragraph pitch.',
  shortDescription: 'Your one-line tagline.',
  url: 'https://your-domain.com',
  links: {
    github: 'https://github.com/yourorg/yourrepo',
    twitter: 'https://twitter.com/yourhandle',
    contact: 'mailto:hello@your-domain.com',
  },
  mail: {
    fromName: 'YourProduct',
    supportEmail: 'support@your-domain.com',
  },
};
```

Keep this file under 250 lines. Domain-heavy logic (pricing math, AI provider
settings) belongs in its own module — see `src/ai/pricing.ts` for the pattern.

## Colors (custom palette beyond the presets)

Tailwind v4 reads tokens from `@theme` in `src/app/globals.css`. Every color is
[OKLCH](https://oklch.com) — perceptually uniform, predictable hue rotation,
copy-paste-friendly with the OKLCH color picker.

Vibestrap is **light-only** — there is no `.dark` class and no system-mode toggle.
If you want a dark variant, see the dark-mode reference doc for a 5-step
opt-in recipe.

The default `cream` theme:

```css theme={null}
.theme-cream {
  --background: oklch(0.96 0.012 85);   /* warm off-white paper */
  --foreground: oklch(0.18 0 0);        /* near-black */
  --primary: oklch(0.18 0 0);
  --primary-foreground: oklch(0.97 0.008 85);
  --accent-tech: oklch(0.55 0.2 250);   /* electric blue — logo cursor + progress bar */
  --accent-tech-light: oklch(0.72 0.16 240);
  /* full set in globals.css */
}
```

Two ways to customize:

1. **Tweak a preset** — edit the OKLCH values inside `.theme-cream` (or `.theme-white` / `.theme-ash`) in `globals.css`. shadcn/ui components consume these tokens by name, so a single edit re-skins everything.
2. **Add a new preset** — duplicate one of the `.theme-*` blocks under a new name, then extend the union in `siteConfig.ui.theme` to include it. The TypeScript types pick it up automatically.

Pick a brand hue with the OKLCH picker. Always swap `--accent-tech` and
`--accent-tech-light` together — the progress-bar gradient interpolates between
them.

## Fonts

The default stack is **Geist Sans** + **Geist Mono**, loaded in `src/app/layout.tsx`
via `next/font/google`:

```tsx theme={null}
import { Geist, Geist_Mono } from 'next/font/google';
const geistSans = Geist({ variable: '--font-geist-sans', subsets: ['latin'] });
const geistMono = Geist_Mono({ variable: '--font-geist-mono', subsets: ['latin'] });
```

Swap in any `next/font/google` import. Update `--font-sans` / `--font-mono` in
`globals.css` to match the CSS variable name and you're done — no Tailwind config
edit needed.

## Marketing copy

All on-page copy lives in `messages/en.json` and `messages/zh.json` under the
`Home` namespace. Both files **must** have identical key structure — next-intl
throws at build time if keys diverge.

```json theme={null}
"Home": {
  "hero": {
    "title": "Your hero title",
    "subtitle": "Your supporting line."
  }
}
```

Hot-reload picks edits up instantly. When you add a new message key, add it to
both files in the same commit.

## Hero / features layout

The home page is a stack of independent blocks composed in
`src/app/[locale]/(marketing)/page.tsx`:

```tsx theme={null}
<Hero />
<LogoCloud />
<Features />
<UseCases />
<WhyVibestrap />
<Quickstart />
<Pricing />
<FAQ />
<NewsletterCard />
<CTA />
```

Reorder or delete any of them. Each block is a self-contained component in
`src/components/blocks/` reading from `messages/{locale}.json` — no prop wiring
across boundaries.

## Pricing

Two distinct pricing surfaces in `siteConfig`:

**For the Vibestrap product itself** (what you sell to your buyers):

```ts theme={null}
product: {
  standardPriceCents: 9900,        // $99
  promo: { active: true, priceCents: 4900 }, // $49 limited offer
}
```

Toggle `promo.active` to flip between the two. The hero, pricing block, and
checkout all read from `activePriceCents()` so a single edit propagates.

**For your buyer's downstream app** (sample subscription + credit pack pricing
they show their own users):

```ts theme={null}
demoPlans: [
  { id: 'lifetime_promo',    type: 'one_time',    priceCents:  4900, priceIdEnv: 'STRIPE_PRICE_VIBESTRAP_PROMO',    creditsGranted:   1000 },
  { id: 'lifetime_standard', type: 'one_time',    priceCents:  9900, priceIdEnv: 'STRIPE_PRICE_VIBESTRAP_STANDARD', creditsGranted:   1000 },
  { id: 'pro_monthly',       type: 'subscription', interval: 'monthly', priceCents:  999, priceIdEnv: 'STRIPE_PRICE_PRO_MONTHLY', creditsGranted:  1000 },
  { id: 'pro_yearly',        type: 'subscription', interval: 'yearly',  priceCents: 9900, priceIdEnv: 'STRIPE_PRICE_PRO_YEARLY',  creditsGranted: 12000 },
]
```

These render as a 2×2 grid in `/settings/credits` showing the four common
pricing patterns. Replace prices, env names, and credit grants with whatever
your buyer's product charges.

## Logo

The default header and footer use the `Sparkles` icon from `lucide-react`.
Replace it in two places:

```tsx theme={null}
// src/components/layout/header.tsx
import { Sparkles } from 'lucide-react';
// → swap for your own SVG component or <Image src="/logo.svg" .../>
<Sparkles className="size-5 text-primary" />
```

Same edit in `src/components/layout/footer.tsx`. For the OG image, replace
`public/og.png` (1200x630, PNG or JPG).

## Email templates

React Email templates live in `src/mail/templates/`:

* `verify-email.tsx` — signup verification.
* `welcome.tsx` — sent after the user verifies.
* `forgot-password.tsx` — password reset link.

Edit them like any React component. Branding (`siteConfig.name`,
`siteConfig.mail.supportEmail`) is already pulled in. To preview locally before
the email-dev script ships, trigger the auth flow and watch the dev console for
the rendered HTML.

## Adding a locale

1. Add the locale code to `src/config/site.ts`:
   ```ts theme={null}
   i18n: { defaultLocale: 'en', locales: ['en', 'zh', 'ja'] }
   ```
2. Create `messages/ja.json` mirroring the key structure of `en.json`.
3. Translate every `*.zh.mdx` to `*.ja.mdx` for any docs you ship.
4. Done. URLs become `/ja/...` automatically.

## See also

* [Configuration](/configuration) — every `siteConfig` field.
* [Architecture](/architecture) — how blocks, themes, and providers wire together.
* [Env reference](/env-reference) — keys that flip features on / off.
