# Technical Plan

## Project Setup

### Location
```
broomer/
├── main/              ← existing Electron app
│   ├── src/
│   ├── scripts/
│   ├── tests/
│   └── package.json
└── website/           ← new Next.js project
    ├── src/
    │   └── app/
    │       ├── layout.tsx
    │       ├── page.tsx
    │       └── globals.css
    ├── public/
    │   └── screenshots/   ← generated by Playwright
    ├── components/
    │   ├── Hero.tsx
    │   ├── FeatureSection.tsx
    │   ├── DownloadButton.tsx
    │   ├── CodeBlock.tsx
    │   ├── TechBadge.tsx
    │   └── Footer.tsx
    ├── next.config.ts
    ├── tailwind.config.ts
    ├── package.json
    └── tsconfig.json
```

The website is a **separate package** with its own `package.json`. It does not share dependencies with the Electron app. This keeps concerns clean and avoids Electron dependencies polluting the web build.

### Tech Stack

| Tool | Purpose |
|------|---------|
| **Next.js 15** (App Router) | Framework — SSG for the marketing page |
| **React 19** | UI library |
| **Tailwind CSS 4** | Styling |
| **TypeScript** | Type safety |
| **Inter** (Google Fonts) | Primary typeface |
| **JetBrains Mono** (Google Fonts) | Code typeface |
| **next/image** | Image optimization (WebP, lazy loading, blur placeholders) |
| **Vercel** | Hosting & deployment |

### Initialization

```bash
cd website
npx create-next-app@latest . --typescript --tailwind --app --src-dir --eslint
```

### `package.json` scripts
```json
{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  }
}
```

## Next.js Configuration

### `next.config.ts`
```typescript
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  output: 'export',           // Static export for Vercel (no server needed)
  images: {
    unoptimized: true,        // For static export — optimize at build time instead
  },
}

export default nextConfig
```

We use `output: 'export'` because the marketing site is entirely static. No API routes, no SSR. This produces a `out/` directory that can be deployed anywhere.

**Alternative**: If we want Vercel's image optimization, remove `output: 'export'` and use Vercel's default deployment. This gives us `next/image` with automatic WebP conversion and responsive sizes. This is the recommended approach if deploying to Vercel.

### Tailwind Configuration

```typescript
// tailwind.config.ts
import type { Config } from 'tailwindcss'

const config: Config = {
  content: [
    './src/**/*.{ts,tsx}',
    './components/**/*.{ts,tsx}',
  ],
  theme: {
    extend: {
      colors: {
        'bg-page':      '#0a0a0a',
        'bg-card':      '#141414',
        'bg-elevated':  '#1a1a1a',
        'border':       '#2a2a2a',
        'border-hover': '#3a3a3a',
        'text-primary': '#f0f0f0',
        'text-body':    '#888888',
        'text-muted':   '#555555',
        'accent':       '#4a9eff',
      },
      fontFamily: {
        sans: ['Inter', '-apple-system', 'BlinkMacSystemFont', 'sans-serif'],
        mono: ['JetBrains Mono', 'SF Mono', 'Fira Code', 'monospace'],
      },
      maxWidth: {
        'content': '1200px',
      },
    },
  },
  plugins: [],
}

export default config
```

## Page Structure

### `src/app/layout.tsx`
```typescript
import { Inter, JetBrains_Mono } from 'next/font/google'
import './globals.css'

const inter = Inter({ subsets: ['latin'], variable: '--font-sans' })
const jetbrainsMono = JetBrains_Mono({ subsets: ['latin'], variable: '--font-mono' })

export const metadata = {
  title: 'Broomy — Command center for AI coding agents',
  description: 'Manage multiple AI coding sessions across repositories. Open source desktop app for developers.',
  openGraph: {
    title: 'Broomy — Command center for AI coding agents',
    description: 'Manage multiple AI coding sessions across repositories.',
    images: ['/screenshots/hero.png'],
  },
}

export default function RootLayout({ children }) {
  return (
    <html lang="en" className={`${inter.variable} ${jetbrainsMono.variable}`}>
      <body className="bg-bg-page text-text-primary font-sans antialiased">
        {children}
      </body>
    </html>
  )
}
```

### `src/app/page.tsx`
```typescript
import Hero from '@/components/Hero'
import Problem from '@/components/Problem'
import FeatureSection from '@/components/FeatureSection'
import Architecture from '@/components/Architecture'
import OpenSource from '@/components/OpenSource'
import GetStarted from '@/components/GetStarted'
import Footer from '@/components/Footer'

export default function Home() {
  return (
    <main>
      <Hero />
      <Problem />
      <FeatureSection
        eyebrow="Multi-session"
        title="See every agent at a glance"
        description="Status indicators show which agents are working, which are idle, and which need your attention. Switch between sessions instantly."
        screenshot="/screenshots/sidebar.png"
        alt="Broomy sidebar showing multiple AI agent sessions with status indicators"
        direction="left"
      />
      {/* ... more FeatureSections ... */}
      <Architecture />
      <OpenSource />
      <GetStarted />
      <Footer />
    </main>
  )
}
```

## Components

### `Hero.tsx`
- Full-width section with generous padding (py-24 lg:py-32)
- Centered headline + subheadline
- Two CTA buttons: **Download for macOS** (primary, white) and **View on GitHub** (secondary, ghost)
- Below: large screenshot in a container with rounded corners and shadow
- The download button links to the latest GitHub Release asset

### `DownloadButton.tsx`
- Prominent white button with Apple logo icon
- Text: "Download for macOS" with smaller "Apple Silicon · v1.0.0" subtitle
- Links to GitHub Releases (e.g., `https://github.com/broomy-ai/broomy/releases/latest`)
- Sticky/floating version also appears in the nav bar on scroll

### `FeatureSection.tsx`
- Reusable component with props: `eyebrow`, `title`, `description`, `screenshot`, `alt`, `direction`
- `direction: 'left' | 'right'` — which side the screenshot goes on
- On mobile, always stacks screenshot on top, text below
- Screenshot uses `next/image` with priority loading for above-fold images

### `CodeBlock.tsx`
- Styled code block for installation commands
- Copy-to-clipboard button
- Bash syntax highlighting (static, no heavy library — just colored spans)

### `TechBadge.tsx`
- Pill-shaped badge showing a technology name
- Used in the Architecture section for the tech stack

### `Footer.tsx`
- Minimal footer with GitHub link, license, and one-line description
- No sitemap, no social links, no newsletter — keep it clean

## Download Strategy

The download experience should be front-and-center. Two approaches:

### Option A: GitHub Releases (recommended for v1)
- The "Download" button links to the latest GitHub Release
- The release contains a `.dmg` for macOS (built via `pnpm dist`)
- Version number fetched at build time via GitHub API and displayed on the button
- If no release exists yet, the button says "Build from Source" and scrolls to the install section

### Option B: Direct download (future)
- Host the `.dmg` on Vercel or a CDN
- Faster download, no GitHub dependency
- Requires automated release pipeline

For v1, GitHub Releases is the right choice — it's standard for open source projects and reinforces the "this is a real OSS project" signal.

### Nav bar
A thin, fixed nav bar appears on scroll with:
- "Broomy" logo/text (left)
- "Download" button (right) — always accessible

## Deployment

### Vercel Configuration

Connect the GitHub repo to Vercel with these settings:

```
Framework Preset: Next.js
Root Directory: website
Build Command: next build      (or: cd website && next build)
Output Directory: .next        (or: out/ if using static export)
Install Command: npm install   (website has its own package.json)
```

### Environment Variables (Vercel)
```
NEXT_PUBLIC_GITHUB_REPO=broomy-ai/broomy
NEXT_PUBLIC_APP_VERSION=1.0.0
```

### Domain
Set up a custom domain (e.g., `broomy.dev` or `getbroomy.com`) in Vercel's dashboard.

### Automatic Deployments
- Every push to `main` triggers a production deploy
- PRs get preview deployments automatically

## Build Pipeline for Screenshots

Screenshots are NOT generated on every Vercel deploy (that would require Electron, which can't run on Vercel's build servers). Instead:

### Local/CI screenshot generation
```bash
# Run from the repo root
cd main
pnpm install
pnpm run generate-screenshots   # Launches Electron, captures screenshots

# Screenshots are saved to website/public/screenshots/
```

### Git-tracked screenshots
The generated screenshots are committed to the repo in `website/public/screenshots/`. This means:
- Vercel just serves them as static assets
- No special build step needed
- Screenshots update when someone runs the generation script and commits

### CI automation (optional, future)
A GitHub Action could:
1. Run on a macOS runner (required for Electron)
2. Generate screenshots
3. Commit them to the repo automatically
4. This ensures screenshots stay up to date as the app evolves

## Performance Targets

- **Lighthouse score**: 95+ on all metrics
- **First Contentful Paint**: < 1s
- **Largest Contentful Paint**: < 2.5s (hero screenshot is the LCP element)
- **Total page weight**: < 2MB (including all screenshots)
- **Time to Interactive**: < 1.5s

### Optimization strategies
- Static export — no server rendering overhead
- `next/image` for automatic WebP, responsive sizes, lazy loading
- Hero screenshot loaded eagerly with `priority` prop
- Other screenshots loaded lazily as they scroll into view
- Inter and JetBrains Mono loaded via `next/font` (no CLS, no FOUT)
- Minimal JS — no client-side interactivity except scroll animations and copy-to-clipboard
