diff --git a/README.md b/README.md index 7527097..ef81e32 100644 --- a/README.md +++ b/README.md @@ -1,104 +1,177 @@
-# Offpage +
+ + + + + Offpage + + +

+ +### Generate websites with AI — entirely on your device. -**Generate websites with AI — entirely on your device.** +No cloud. No API keys. No subscriptions. Full privacy. -No cloud. No API calls. Full privacy. +
-[![Windows](https://img.shields.io/badge/Windows-0078D6?style=for-the-badge&logo=windows&logoColor=white)](#) -[![macOS](https://img.shields.io/badge/macOS-000000?style=for-the-badge&logo=apple&logoColor=white)](#) -[![License](https://img.shields.io/badge/License-TBD-444?style=for-the-badge)](#) +[![GitHub Stars](https://img.shields.io/github/stars/Szymon0C/Offpage?style=flat&logo=github&color=f5c542)](https://github.com/Szymon0C/Offpage) +[![Windows](https://img.shields.io/badge/-Windows-0078D6?style=flat&logo=windows11&logoColor=white)](#download) +[![macOS](https://img.shields.io/badge/-macOS-000000?style=flat&logo=apple&logoColor=white)](#download) +[![Built with Tauri](https://img.shields.io/badge/Built_with-Tauri-FFC131?style=flat&logo=tauri&logoColor=white)](https://tauri.app) +[![License: MIT](https://img.shields.io/badge/License-MIT-blue?style=flat)](#license)
Offpage Preview -^ screenshot coming soon +screenshot coming soon -
+

+ +[**Download**](#download)  ·  [**Getting Started**](#getting-started)  ·  [**Features**](#features)  ·  [**Contributing**](#contributing)
+ + +--- + ## Features - -
+ -### Generate from a prompt -Describe what you want — AI builds the entire page from scratch. +**Prompt to page** — Describe what you want, AI generates the entire website from scratch. -### Start from templates -Pick a template, customize it with natural language. +**Template gallery** — Start from curated templates and customize with natural language. -### Chat editing -*"Change the header to dark blue"* — and it's done. +**Chat editing** — *"Make the header dark blue and add a CTA button"* — done. + -### Inline editing -Click any section on the page, prompt changes just for that part. +**Inline editing** — Click any section, prompt changes just for that part. -### Visual editing -Edit text, colors, and images directly — no code needed. +**Visual editing** — Edit text directly on the page — WYSIWYG, no code. -### One-click deploy -Publish to Netlify, Vercel, or GitHub Pages instantly. +**One-click deploy** — Publish to Netlify, Vercel, or GitHub Pages instantly.
+> Output is a single HTML file with inline CSS/JS — works everywhere. > Supports landing pages, portfolios, blogs, and static e-commerce. -> Output is a single HTML file with inline CSS/JS — works everywhere.
-## Tech Stack +## How It Works ``` -Frontend React 19 · TypeScript · Vite · Tailwind CSS 4 · Zustand · Pretext -Desktop Tauri 2.0 (Rust) -AI llama.cpp sidecar · Qwen2.5-Coder 7B (3B fallback) -GPU Metal (macOS) · CUDA / Vulkan (Windows) -Storage SQLite + You type a prompt + │ + ▼ + ┌──────────┐ Tauri IPC ┌──────────────┐ HTTP ┌──────────────┐ + │ Frontend │ ◄────────────► │ Rust Core │ ◄───────► │ llama.cpp │ + │ React 19 │ │ (Tauri 2.0) │ │ (local AI) │ + └──────────┘ └──────────────┘ └──────────────┘ + │ │ + │ postMessage │ SQLite + ▼ ▼ + ┌──────────┐ ┌──────────────┐ + │ Preview │ │ Storage │ + │ (iframe) │ │ Projects │ + └──────────┘ └──────────────┘ ``` +Everything runs locally. The AI model is downloaded once and stays on your machine. + +
+ +## Tech Stack + +| Layer | Technology | +|:------|:-----------| +| **Frontend** | React 19 · TypeScript · Vite · Tailwind CSS 4 · Zustand | +| **Desktop** | Tauri 2.0 (Rust) | +| **AI** | llama.cpp sidecar · Qwen2.5-Coder-7B (3B fallback) | +| **GPU** | Metal (macOS) · CUDA / Vulkan (Windows) | +| **Storage** | SQLite | +| **Deploy** | Netlify · Vercel · GitHub Pages | +
-## Architecture +## Getting Started + +### Prerequisites + +- **Node.js** 18+ — [nodejs.org](https://nodejs.org) +- **Rust** — [rustup.rs](https://rustup.rs) +- **pnpm** (recommended) or npm + +
+macOS extras + +```bash +xcode-select --install +``` + +
+ +
+Windows extras + +Install [Microsoft C++ Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/) and [WebView2](https://developer.microsoft.com/en-us/microsoft-edge/webview2/). + +
+ +### Clone & Install + +```bash +git clone https://github.com/Szymon0C/Offpage.git +cd Offpage +pnpm install # or: npm install +``` + +### Download the AI sidecar +```bash +bash scripts/setup-sidecar.sh ``` -┌──────────────────────────────────────────────────────┐ -│ Tauri Shell (Rust) │ -│ │ -│ File Manager · AI Sidecar · Deploy Service │ -│ HW Detector · SQLite Store · Auto Updater │ -│ │ -├─────────────────────── IPC ──────────────────────────┤ -│ │ -│ Frontend (Webview) │ -│ │ -│ Chat Panel · Preview Manager · WYSIWYG Engine │ -│ │ -├────────────────── postMessage ───────────────────────┤ -│ │ -│ Preview iframe (isolated) │ -│ │ -│ User's HTML · Offpage Helper Script │ -│ │ -└──────────────────────────────────────────────────────┘ + +This downloads the pre-built `llama-server` binary for your platform (~50 MB). + +### Run in development + +```bash +pnpm tauri dev # or: npx tauri dev +``` + +The app will open automatically. On first launch: + +1. Hardware detection runs automatically +2. Choose a model (7B recommended for 16 GB+ RAM, 3B for 8 GB) +3. Click **Download & Start AI** — one-time download from Hugging Face +4. Start chatting! + +### Build for production + +```bash +pnpm tauri build # or: npx tauri build ``` +Builds a distributable `.dmg` (macOS) or `.msi` / `.exe` (Windows) in `src-tauri/target/release/bundle/`. +
## Hardware Requirements | | Hardware | Experience | |:--|:---------|:-----------| -| **Minimum** | 8 GB RAM, x64 (AVX2) or Apple Silicon | Works — CPU inference, slower | +| **Minimum** | 8 GB RAM, x64 (AVX2) or Apple Silicon | Works — CPU inference, slower | | **Recommended** | 16 GB RAM, 6 GB+ VRAM or M1+ | Smooth generation | | **Optimal** | 32 GB RAM, RTX 3060+ or M1 Pro+ | Fast, room for larger models | @@ -106,12 +179,61 @@ The app detects your hardware and adjusts automatically (quantization, model siz
-## Status +## Project Structure + +``` +Offpage/ +├── src/ # React frontend +│ ├── components/ # UI components (chat, preview, deploy, templates) +│ ├── stores/ # Zustand state (project, chat, editor, ai, deploy) +│ ├── pages/ # Route pages (Home, Project, Templates, Settings) +│ ├── hooks/ # Custom hooks (useAiStream) +│ ├── lib/ # Utilities (prompts, templates, deploy providers) +│ └── db/ # SQLite database, migrations +├── src-tauri/ # Rust backend +│ └── src/ +│ ├── ai.rs # SSE streaming from llama-server +│ ├── sidecar.rs # llama-server lifecycle management +│ ├── models.rs # Model download & management +│ ├── deploy.rs # Deploy to Netlify/Vercel/GitHub Pages +│ └── hardware.rs # Hardware detection (RAM, GPU, CPU) +├── scripts/ # Setup scripts +└── docs/ # Specs, plans, assets +``` + +
+ +## Contributing -> **Early development** — architecture designed, implementation starting. +Contributions are welcome! This project is in early development — there's plenty to do. + +```bash +# Fork & clone the repo, then: +pnpm install +bash scripts/setup-sidecar.sh +pnpm tauri dev +``` + +Please open an issue before submitting large PRs so we can discuss the approach. + +
+ +## Download + +> **Coming soon** — Early development builds will be available once the core features are stable. + +Watch this repo or star it to get notified.
## License -TBD +MIT — see [LICENSE](LICENSE) for details. + +
+ +
+ +Built with Tauri, React, and local AI. No data leaves your device. + +
diff --git a/docs/superpowers/plans/2026-04-02-phase4-templates.md b/docs/superpowers/plans/2026-04-02-phase4-templates.md new file mode 100644 index 0000000..c1c9945 --- /dev/null +++ b/docs/superpowers/plans/2026-04-02-phase4-templates.md @@ -0,0 +1,827 @@ +# Phase 4: Templates — Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Build a template gallery where users browse bundled HTML templates by category, preview them, and create new projects from templates — optionally with AI customization. + +**Architecture:** Templates are stored as HTML strings in SQLite (seeded on first launch). The TemplatesPage displays a grid of template cards with category filtering. Selecting a template creates a new project pre-populated with the template HTML. Users can optionally provide a customization prompt that sends the template + prompt to AI for modification before saving. + +**Tech Stack:** React 19, TypeScript, Zustand, SQLite (tauri-plugin-sql), Tailwind CSS 4 + +--- + +## File Structure + +### New Files +| File | Responsibility | +|------|---------------| +| `src/stores/templateStore.ts` | Zustand store: load templates from DB, filter by category | +| `src/lib/bundledTemplates.ts` | Bundled template HTML strings + metadata for seeding DB | +| `src/components/templates/TemplateCard.tsx` | Card component showing template name, category, preview thumbnail | +| `src/components/templates/TemplatePreviewModal.tsx` | Modal with full-size template preview + "Use Template" action | + +### Modified Files +| File | Changes | +|------|---------| +| `src/pages/TemplatesPage.tsx` | Replace placeholder with template gallery grid + category filter | +| `src/pages/HomePage.tsx` | Add "From Template" button alongside "New Project" | +| `src/db/database.ts` | Add template seeding on first launch | + +--- + +### Task 1: Bundled Templates + +**Files:** +- Create: `src/lib/bundledTemplates.ts` + +Four templates — one per category. Each is a complete single-file HTML page. + +- [ ] **Step 1: Create bundled templates file** + +```typescript +// src/lib/bundledTemplates.ts + +export interface BundledTemplate { + id: string; + name: string; + category: 'landing' | 'portfolio' | 'blog' | 'ecommerce'; + version: string; + html: string; +} + +export const BUNDLED_TEMPLATES: BundledTemplate[] = [ + { + id: 'tpl-landing-startup', + name: 'Startup Landing', + category: 'landing', + version: '1.0.0', + html: ` + + + + +Startup Name + + + +
+

Build Something Amazing

+

The fastest way to launch your next big idea. Simple, powerful, and designed for teams that move fast.

+Get Started Free +
+
+

Why Choose Us

+
+

Lightning Fast

Optimized for speed from the ground up. Your users will notice the difference immediately.

+

Easy to Use

No technical knowledge required. Get up and running in minutes, not hours.

+

Secure by Default

Enterprise-grade security built in. Your data is encrypted and protected at every level.

+
+
+ + +`, + }, + { + id: 'tpl-portfolio-minimal', + name: 'Minimal Portfolio', + category: 'portfolio', + version: '1.0.0', + html: ` + + + + +Portfolio + + + +
+

Jane Designer

+

Product designer crafting thoughtful digital experiences.

+ +
+
+

Selected Work

+
+
Project Image

Brand Redesign

Visual identity · 2026

+
Project Image

Mobile App

UI/UX Design · 2025

+
Project Image

E-commerce Platform

Web Design · 2025

+
+
+ + +`, + }, + { + id: 'tpl-blog-clean', + name: 'Clean Blog', + category: 'blog', + version: '1.0.0', + html: ` + + + + +My Blog + + + +
+

Thoughts & Words

+

A personal blog about design, technology, and life.

+
+
+

The Art of Simplicity

March 15, 2026 · 5 min read

Simplicity is the ultimate sophistication. In a world overwhelmed by complexity, the ability to distill ideas to their essence is more valuable than ever. This post explores how minimalism in design leads to better user experiences.

+

Building for the Future

March 8, 2026 · 8 min read

Technology moves fast, but good design principles remain constant. Here are the timeless patterns I keep coming back to when building products that need to last.

+

Morning Routines That Work

February 28, 2026 · 4 min read

After years of experimentation, I've found a morning routine that actually sticks. It's simpler than you'd think and doesn't require waking up at 5 AM.

+
+ + +`, + }, + { + id: 'tpl-ecommerce-store', + name: 'Product Store', + category: 'ecommerce', + version: '1.0.0', + html: ` + + + + +Store + + + +

STORE

+
+

New Season Arrivals

+

Discover our latest collection of premium products.

+Shop Now +
+
+

Featured Products

+
+
Product Image

Classic White Tee

$49

+
Product Image

Leather Backpack

$129$159

+
Product Image

Minimalist Watch

$199

+
Product Image

Canvas Sneakers

$89

+
+
+ + +`, + }, +]; +``` + +- [ ] **Step 2: Verify TypeScript compiles** + +Run: `npx tsc --noEmit` + +- [ ] **Step 3: Commit** + +```bash +git add src/lib/bundledTemplates.ts +git commit -m "feat: add bundled HTML templates for all four categories" +``` + +--- + +### Task 2: Template Store + +**Files:** +- Create: `src/stores/templateStore.ts` + +- [ ] **Step 1: Create the template store** + +```typescript +// src/stores/templateStore.ts +import { create } from 'zustand'; +import { getDatabase } from '../db/database'; +import type { SiteType } from '../types/project'; + +export interface Template { + id: string; + name: string; + category: SiteType; + html: string; + version: string; +} + +interface TemplateState { + templates: Template[]; + filter: SiteType | 'all'; + loading: boolean; + loadTemplates: () => Promise; + setFilter: (filter: SiteType | 'all') => void; + filteredTemplates: () => Template[]; +} + +export const useTemplateStore = create((set, get) => ({ + templates: [], + filter: 'all', + loading: false, + + loadTemplates: async () => { + set({ loading: true }); + try { + const db = await getDatabase(); + const templates = await db.select( + 'SELECT id, name, category, html, version FROM templates ORDER BY category, name' + ); + set({ templates, loading: false }); + } catch (error) { + console.error('Failed to load templates:', error); + set({ loading: false }); + } + }, + + setFilter: (filter) => set({ filter }), + + filteredTemplates: () => { + const { templates, filter } = get(); + if (filter === 'all') return templates; + return templates.filter((t) => t.category === filter); + }, +})); +``` + +- [ ] **Step 2: Verify TypeScript compiles** + +Run: `npx tsc --noEmit` + +- [ ] **Step 3: Commit** + +```bash +git add src/stores/templateStore.ts +git commit -m "feat: add template store with category filtering" +``` + +--- + +### Task 3: Seed Templates on First Launch + +**Files:** +- Modify: `src/db/database.ts` + +Add a seeding function that inserts bundled templates if the templates table is empty. + +- [ ] **Step 1: Add seed function** + +After the existing `getDatabase` function, add template seeding. Import `BUNDLED_TEMPLATES` from `../lib/bundledTemplates` and call `seedTemplates(db)` inside the init function, after migrations. + +The seed function: + +```typescript +import { BUNDLED_TEMPLATES } from '../lib/bundledTemplates'; + +async function seedTemplates(db: Database): Promise { + const rows = await db.select>('SELECT COUNT(*) as count FROM templates'); + if (rows[0]?.count > 0) return; + + for (const tpl of BUNDLED_TEMPLATES) { + await db.execute( + 'INSERT INTO templates (id, name, category, html, thumbnail, version) VALUES (?, ?, ?, ?, NULL, ?)', + [tpl.id, tpl.name, tpl.category, tpl.html, tpl.version] + ); + } +} +``` + +Call `await seedTemplates(db)` after the migration `db.execute(CREATE TABLE...)` calls complete inside the database init function. + +- [ ] **Step 2: Verify TypeScript compiles** + +Run: `npx tsc --noEmit` + +- [ ] **Step 3: Commit** + +```bash +git add src/db/database.ts +git commit -m "feat: seed bundled templates into DB on first launch" +``` + +--- + +### Task 4: TemplateCard Component + +**Files:** +- Create: `src/components/templates/TemplateCard.tsx` + +- [ ] **Step 1: Create TemplateCard** + +```tsx +// src/components/templates/TemplateCard.tsx +import type { SiteType } from '../../types/project'; + +interface TemplateCardProps { + id: string; + name: string; + category: SiteType; + html: string; + onSelect: (id: string) => void; +} + +const CATEGORY_COLORS: Record = { + landing: 'bg-indigo-500/20 text-indigo-400', + portfolio: 'bg-emerald-500/20 text-emerald-400', + blog: 'bg-amber-500/20 text-amber-400', + ecommerce: 'bg-rose-500/20 text-rose-400', +}; + +export function TemplateCard({ id, name, category, html, onSelect }: TemplateCardProps) { + return ( +