# Landing templates: rebrand every section from one site.ts, not a ghost regenerate

> Rebrand OTF landing templates from src/content/site.ts; sections stay owned; bun build to Cloudflare Pages — not a ghost regenerate.
> By Dave · 2026-09-19
> Source: https://otf-kit.dev/blog/landing-templates-site-ts-rebrand

Every landing template in the OTF pack puts brand copy and imagery in one typed file: `src/content/site.ts`. Section components under `src/sections/` read that object — they do not hard-code headlines, region cards, or photo alts. That split is the rebrand contract. Edit `site.ts` (and the shipped AI prompts that point agents at it), run `bun run build`, deploy the static `dist/` to Cloudflare Pages. You keep the architecture. You do not ask a sandbox to regenerate a lookalike page you cannot open in git.

This post is that `site.ts` rebrand path. It is not the general "own the repo" overview — that lives at [/blog/landing-templates-kit-own-the-repo](/blog/landing-templates-kit-own-the-repo). It is not the broader "how to build a landing page with AI" guide — that is [/blog/how-to-build-a-landing-page-with-ai](/blog/how-to-build-a-landing-page-with-ai). Those posts cover ownership and assembly order. Here the question is narrower: after checkout, how do you rebrand Summit (or Aura, or any of the fifteen) without turning sections into a second content store an agent invents beside the typed config.

## What the landing pack already ships

OTF lists the fifteen industry templates on [https://otf-kit.dev/templates](https://otf-kit.dev/templates). Each is sold standalone at $9; all fifteen are included in the kit bundle. Every template is a self-contained Vite + React + TypeScript app that builds to static output — no backend, no accounts, no hosted editor lock-in. Live demos you can click before buying include [https://summit.otf-kit.dev](https://summit.otf-kit.dev) (travel / expeditions) and [https://aura.otf-kit.dev](https://aura.otf-kit.dev) (SaaS / app landing).

Canonical pack facts (from the internal landing-pack index buyers mirror after sync):

- Fifteen templates: Summit, Lumen, Maison, Solène, Tempo, Volt, Monolith, Resonance, Orbit, Gallery, Atelier, Frame, Still, Apex, Aura
- Shared layout: `src/sections/` (one file per section), `src/content/site.ts` (all copy + imagery), `src/theme/` (theme system), `src/lib/` (shared `HeroCanvas`, `Reveal`, `SlotImage`), `src/index.css` (design system)
- WebGL hero via shared `HeroCanvas` — lazy-loaded, reduced-motion-safe, pauses off-screen
- Theme system — light/dark plus palettes, switchable from the nav, persisted to `localStorage`
- AI-tool config — `CLAUDE.md`, `.cursorrules`, and tested prompts under `ai/prompts/` (including `swap-copy.md` and `swap-imagery.md` on Summit)
- Build: `bun install` → `bun dev` → `bun run build` → deploy-ready `dist/`

Summit is the locked reference pattern; templates 02–15 are re-skins of that structure. When you learn the Summit file map, you learn the pack.

## Why ghost regenerates fail buyers (and agents)

Three failure modes show up the week after purchase:

1. **Copy baked into JSX** — an agent rewrites `Hero.tsx` and `Regions.tsx` with new strings. The next prompt that edits `site.ts` does nothing visible, and two sources of truth drift.
2. **Sandbox regenerate** — a prompt asks a hosted builder to "make a new travel landing like Summit." You get a screenshot-shaped page with no `site.ts`, no `HeroCanvas` reduced-motion gate, and no Cloudflare Pages `dist/` you control.
3. **Parallel content module** — an agent invents `content/pages.json` or a CMS stub beside the typed `site` object. Sections start importing the new store; the shipped prompts that say "edit `site.ts` only" become lies.

The honest path is the one Summit documents in `CLAUDE.md`: all page content lives in `src/content/site.ts` as one typed `site` object. Section components never hard-code copy, so a content change should not touch any `sections/*.tsx` file.

![One-way path: edit site.ts so section tiles update; no parallel pages.json](https://cdn.otf-kit.dev/blog/landing-templates-site-ts-rebrand/inbody1-20260919e.png)

## The owned rebrand contract: site.ts in, sections stay architecture

Treat rebrand as a content write against one typed object:

1. **Identity** — brand name, glyph, nav links, and CTAs live on `site.brand` / `site.nav` (and the matching CTA blocks). Do not fork a second brand constant inside `Nav.tsx`.
2. **Hero** — eyebrow, title lines, subtitle, primary/secondary CTAs, stats, `videoSrc`, and `videoPoster` image slot stay on `site.hero`. Clear `videoSrc` to fall back to the still poster; under `prefers-reduced-motion` the canvas is not mounted and the poster `<img>` renders.
3. **Section arrays** — regions, experiences, lodges, trails, journal (Summit's nine-section page order) keep the same shape and field counts the layouts expect. The shipped `swap-copy.md` prompt says it explicitly: keep array lengths so grids stay full; change alts with the copy; do not edit `src/sections/`.
4. **Imagery** — every photo position is a typed `ImageSlot`: `{ src, gradient, alt }`. Empty `src` uses the gradient stand-in; a real URL or imported asset renders the photo. Summit ships curated assets via a `photo()` helper pointed at the OTF landing-pack CDN — swap `src` for your own URLs when you rebrand.
5. **AI handoff** — open Cursor or Claude Code on the buyer repo. Prefer the tested prompts under `ai/prompts/` (`swap-copy.md`, `swap-imagery.md`, plus theme/recolor prompts) over a free-form "rebuild the landing." Point the agent at `CLAUDE.md` and `.cursorrules` so hard constraints stay in force: OTF tokens only, WebGL scoped to `HeroCanvas`, no inventing a parallel content store.
6. **Build and deploy** — `bun run build` produces static `dist/`. Deploy to Cloudflare Pages (build command `bun run build`, output `dist`) or upload `dist/` directly. Custom domain is a Pages setting, not a sandbox publish button.

Illustrative edit shape (labeled sketch — not a private dump of a buyer's live file):

```ts
// Illustrative site.ts rebrand — edit the typed site object only
import type { SiteContent } from "./site"; // your template's exported types

export const site: SiteContent = {
  brand: { name: "Brevik", glyph: "B" },
  nav: { links: ["Regions", "Experiences", "Journal"], cta: "Plan a trip" },
  hero: {
    eyebrow: "Guided fjord expeditions",
    titleLines: [{ text: "Where the water" }, { text: "holds still.", italic: true }],
    subtitle: "Small-group kayaking on Norway's quiet inlets.",
    primaryCta: "Find an expedition",
    secondaryCta: "Watch the film",
    // videoSrc / videoPoster / stats stay on the same hero object
  },
  // regions, experiences, lodges, trails, journal, bookingCta, footer…
  // Keep array lengths; update ImageSlot.alt with the new copy
};
```

After the edit, run `bun dev` to verify sections still fill, then `bun run build` and confirm `dist/` is what Cloudflare Pages will serve.

## Keep ai/prompts as the rebrand path, not a second page

After you clone a buyer repo (Summit example: `otf-kit/summit-landing` after sync), do not prompt "regenerate a landing page." Prefer a bounded job:

```text
Read CLAUDE.md, .cursorrules, and ai/prompts/swap-copy.md.
1) Rewrite site.ts copy for [your business] — same field shapes and array lengths
2) Update ImageSlot.alt text to match; leave section JSX untouched
3) Do not invent content/pages.json or hard-code strings in sections/*.tsx
4) Keep HeroCanvas reduced-motion behavior; do not add 3D outside lib/HeroCanvas.tsx
5) Run bun run build and confirm dist/ is the deploy artifact
```

For imagery-only swaps, use `ai/prompts/swap-imagery.md` the same way: change `ImageSlot.src` (and alts), keep layout code. For palette work, use the theme system already wired in `src/theme/` and `src/index.css` — nav switcher + `localStorage` — instead of pasting hex into section files. Aura's live page even boots palette/mode from `localStorage` before first paint so the first frame matches the buyer's last choice.

![bun run build produces owned dist/ for Cloudflare Pages, not a sandbox preview](https://cdn.otf-kit.dev/blog/landing-templates-site-ts-rebrand/inbody2-20260919e.png)

## Acceptance checks before you call the rebrand done

Run these before you tell a teammate (or an agent) the page is "rebranded":

1. **Grep the sections** — no brand-new marketing strings in `src/sections/` that should have lived in `site.ts`.
2. **Shape intact** — region/experience/journal arrays still match the counts the grids expect (Summit's swap-copy prompt: 4 regions, 3 experiences, 3 trails, 3 journal articles).
3. **Hero honesty** — with reduced motion enabled, you see the poster, not a stuck WebGL canvas; with motion on, the shared displacement hero still lazy-loads.
4. **Theme survives refresh** — palette/mode choice from the nav still restores from `localStorage`.
5. **Static artifact** — `bun run build` exits clean and `dist/` is what you point Cloudflare Pages at — not a temporary preview URL from a sandbox.
6. **Prompt library still true** — `ai/prompts/swap-copy.md` still describes the real edit surface. If you invented a second content module, delete it and put the copy back in `site.ts`.

That checklist is the difference between owning a template and renting a regenerate. The pack already paid for the architecture: nine Summit sections (nav → hero → regions → experiences → lodges → trails → journal → booking CTA → footer), shared `HeroCanvas`, theme switcher, and AI configs. Your job after buy is to change the typed content object and ship `dist/`.

## What this is not

- Not a CMS migration guide — there is no backend in these templates.
- Not a marketplace listing how-to — marketplace is not a shipping kit lane for this blog.
- Not a rewrite of [/blog/landing-templates-kit-own-the-repo](/blog/landing-templates-kit-own-the-repo) (ownership + agent docs) or [/blog/how-to-build-a-landing-page-with-ai](/blog/how-to-build-a-landing-page-with-ai) (generic assembly). Those stay the siblings; this post is the `site.ts` write-path only.

If you need a different industry skin, start from the matching live demo on the [templates catalog](https://otf-kit.dev/templates), confirm the same `site.ts` + `sections/` split, and run the same prompt discipline. The filenames stay familiar across the fifteen because Summit locked the pattern on purpose.

## Sources

- [https://otf-kit.dev/templates](https://otf-kit.dev/templates) — storefront listing for all fifteen landing templates ($9 each; bundle includes all)
- [https://summit.otf-kit.dev](https://summit.otf-kit.dev) — live Summit travel / expeditions demo
- [https://aura.otf-kit.dev](https://aura.otf-kit.dev) — live Aura SaaS / app demo (theme boot from `localStorage`)
- [https://otf-kit.dev/pricing](https://otf-kit.dev/pricing) — kit and bundle pricing
- [https://otf-kit.dev/blog/landing-templates-kit-own-the-repo](https://otf-kit.dev/blog/landing-templates-kit-own-the-repo) — ownership + agent-docs sibling
- [https://otf-kit.dev/blog/how-to-build-a-landing-page-with-ai](https://otf-kit.dev/blog/how-to-build-a-landing-page-with-ai) — generic landing how-to sibling
- Summit buyer-repo docs (`CLAUDE.md`, `.cursorrules`, `ai/prompts/swap-copy.md`, `ai/prompts/swap-imagery.md`) — file map, `site.ts` contract, build → Cloudflare Pages