mirror of
https://github.com/bretzel-app/crumbs.git
synced 2026-10-14 12:28:18 +02:00
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
323 lines
11 KiB
Markdown
323 lines
11 KiB
Markdown
# Screenshot Automation for Landing Page
|
||
|
||
## Overview
|
||
|
||
A Playwright-based script that seeds the Crumbs app with bretzel-themed demo data, captures 10 screenshots (7 desktop + 3 mobile) for the landing page, and commits them. Triggered manually via a GitHub Actions workflow.
|
||
|
||
## Architecture
|
||
|
||
```
|
||
scripts/
|
||
screenshots.ts # Main orchestrator: seed + capture
|
||
fixtures/
|
||
bretzel-pixel.ts # Generates a pixel-art bretzel PNG programmatically
|
||
```
|
||
|
||
Single script (`scripts/screenshots.ts`) that:
|
||
1. Spawns the preview server as a child process (`pnpm preview --port 4173`), same approach as `playwright.config.ts` uses for e2e tests. The app uses `@sveltejs/adapter-node`, so `vite preview` import won't work — must spawn via CLI.
|
||
2. Deletes any existing screenshot DB to start fresh
|
||
3. Seeds data via API calls (setup admin, login, create notes/users/keys)
|
||
4. Navigates to each view and captures screenshots at specific viewports
|
||
5. Saves PNGs directly to `website/assets/`
|
||
6. Kills the preview server in `finally` block
|
||
|
||
## Seed Data — Bretzel Universe
|
||
|
||
### Users
|
||
|
||
| User | Email | Role | Purpose |
|
||
|------|-------|------|---------|
|
||
| Bretzel Admin | admin@bretzel.app | admin | Main user, owns all notes |
|
||
| Alice Chen | alice@bretzel.app | user | Collaborator for sharing screenshot |
|
||
|
||
### Tags
|
||
|
||
Passed explicitly in the `tags` array of each `POST /api/notes` request body: `baking`, `bretzel`, `dev`, `devops`, `homelab`, `personal`, `reading`, `weekend`. Tags are NOT auto-parsed from hashtags in content — they must be provided as a separate field.
|
||
|
||
### Notes
|
||
|
||
| # | Title | Color | Mode | Tags | Pinned | Special |
|
||
|---|-------|-------|------|------|--------|---------|
|
||
| 1 | Bretzel Ingredients | sand | checklist | #baking, #bretzel | yes | Checklist items (see below) |
|
||
| 2 | Self-Hosting Stack | fog | rich text | #homelab, #devops | no | Homelab list (see below) |
|
||
| 3 | Back to Retro Gaming | peach | rich text | #reading, #personal | no | Retro gaming note |
|
||
| 4 | The Best Software Is the Software You Own | coral | rich text | #personal, #bretzel | no | Self-hosting manifesto |
|
||
| 5 | Weekend Plans | mint | rich text | #personal, #weekend | no | Casual weekend plans |
|
||
| 6 | Ancient Flute Harmonica Discovered | chalk | rich text | #reading | no | Quirky news note |
|
||
| 7 | Baking code for the... | clay | checklist | #dev, #bretzel | no | Dev/baking crossover |
|
||
|
||
### Note Content Details
|
||
|
||
**Bretzel Ingredients** (checklist):
|
||
- [x] 500g bread flour
|
||
- [x] 300ml warm water
|
||
- [x] 10g salt
|
||
- [ ] 7g dry yeast
|
||
- [ ] 30g butter (softened)
|
||
- [ ] Baking soda for the bath
|
||
- [ ] Coarse salt for topping
|
||
|
||
**Self-Hosting Stack** (rich text — used for editor screenshot):
|
||
```
|
||
Current homelab setup:
|
||
|
||
**Crumbs** — notes (obviously)
|
||
**42** — holiday budget tracking
|
||
**Dokploy** — deployment platform
|
||
**Outline** — team wiki
|
||
**Navidrome** — music streaming
|
||
**Vaultwarden** — passwords
|
||
**Nextcloud** — files & calendar
|
||
**Plausible** — analytics
|
||
|
||
Everything below daily reverse proxy.
|
||
```
|
||
|
||
**The Best Software Is the Software You Own** (rich text):
|
||
```
|
||
Self-host everything. Trust no cloud.
|
||
|
||
The best software is the software you own.
|
||
Your data. Your server. Your rules.
|
||
|
||
If it can't run on your hardware, it's not really yours.
|
||
```
|
||
|
||
**Back to Retro Gaming** (rich text):
|
||
```
|
||
Games to replay this summer:
|
||
|
||
Chrono Trigger (SNES) — best RPG ever made
|
||
The Legend of Zelda: Link's Awakening (GB)
|
||
Castlevania: Symphony of the Night (PS1)
|
||
Advance Wars (GBA)
|
||
Final Fantasy Tactics (PS1)
|
||
|
||
The pixel art era was peak game design.
|
||
```
|
||
|
||
**Weekend Plans** (rich text):
|
||
```
|
||
Saturday:
|
||
- Farmer's market (get sourdough starter)
|
||
- Fix the Dokploy SSL cert renewal
|
||
- Bake a batch of bretzels
|
||
|
||
Sunday:
|
||
- Retro gaming marathon
|
||
- Update the self-hosting stack
|
||
- Plan next trip on 42
|
||
```
|
||
|
||
**Ancient Flute Harmonica Discovered** (rich text):
|
||
```
|
||
Archaeologists found a 40,000-year-old flute carved from vulture bone.
|
||
|
||
The oldest known musical instrument.
|
||
Imagine the first song ever played.
|
||
```
|
||
|
||
**Baking code for the...** (checklist):
|
||
```
|
||
- [x] Set up CI/CD pipeline
|
||
- [x] Write the CRDT sync logic
|
||
- [ ] Bake the docker image
|
||
- [ ] Deploy to the homelab
|
||
- [ ] Celebrate with a bretzel
|
||
```
|
||
|
||
### Image Attachments
|
||
|
||
**Pixel-art bretzel image** (`scripts/fixtures/bretzel-pixel.ts`):
|
||
- Generated programmatically as a PNG using raw pixel data (no external dependencies)
|
||
- ~64x64 pixel grid, bretzel shape in warm browns (#C8860A gold, #8B6914 dark, #F0E6D3 parchment bg)
|
||
- Attached as featured image to "Bretzel Ingredients" note
|
||
- Also create a second smaller image attached to the same note (e.g. a pixel-art salt shaker or oven) for visual variety
|
||
|
||
### Version History
|
||
|
||
Send 4-5 `PATCH /api/notes/:id` calls to "Self-Hosting Stack" with varying content. Version history entries are created as a side-effect of each PATCH — there is no explicit "create version" endpoint. Each version adds or changes a tool in the stack, so the diff is meaningful when viewed in the history panel.
|
||
|
||
### API Keys
|
||
|
||
Create via API after seeding:
|
||
| Name | Purpose |
|
||
|------|---------|
|
||
| Claude Code | For MCP integration screenshot |
|
||
| N8N | For automation screenshot |
|
||
|
||
## Screenshot Capture Plan
|
||
|
||
### Desktop (1280x800)
|
||
|
||
| # | Filename | View | Capture Steps |
|
||
|---|----------|------|---------------|
|
||
| 1 | screenshot-grid.png | Home grid | Navigate to `/`, wait for notes to render, ensure sidebar is expanded with tags visible |
|
||
| 2 | screenshot-editor.png | Note editor | Click "Self-Hosting Stack" note, wait for editor to open with content and toolbar visible |
|
||
| 3 | screenshot-checklist.png | Checklist mode | Click "Bretzel Ingredients" note, wait for checklist items with checkboxes visible |
|
||
| 4 | screenshot-sharing.png | Share dialog | Open a note, click share button, wait for ShareDialog with "Alice Chen" listed as collaborator |
|
||
| 5 | screenshot-history.png | Version history | Open "Self-Hosting Stack", click history button, select a middle version in the list, wait for preview panel |
|
||
| 6 | screenshot-attachments.png | Attachments | Open "Bretzel Ingredients" note (has featured bretzel image), ensure image thumbnails and featured strip visible |
|
||
| 7 | screenshot-api.png | Settings > API/MCP | Navigate to `/settings/mcp`, wait for API keys list ("Claude Code", "N8N") and MCP config JSON block |
|
||
|
||
### Mobile (390x844)
|
||
|
||
| # | Filename | View | Capture Steps |
|
||
|---|----------|------|---------------|
|
||
| 1 | screenshot-mobile-grid.png | Home grid | Navigate to `/`, wait for notes in mobile layout (no sidebar, tags as horizontal pills) |
|
||
| 2 | screenshot-mobile-editor.png | Note editor | Open "Self-Hosting Stack" note, wait for mobile editor |
|
||
| 3 | screenshot-mobile-checklist.png | Checklist | Open "Bretzel Ingredients" note, wait for mobile checklist view |
|
||
|
||
### Capture Settings
|
||
- Format: PNG
|
||
- Full page: false (viewport only)
|
||
- Animations disabled via `page.emulateMedia({ reducedMotion: 'reduce' })` to avoid capturing mid-animation
|
||
- Wait for `networkidle` after each navigation before capturing
|
||
|
||
## GitHub Actions Workflow
|
||
|
||
**File**: `.github/workflows/screenshots.yml`
|
||
|
||
```yaml
|
||
name: Screenshots
|
||
|
||
on:
|
||
workflow_dispatch:
|
||
|
||
permissions:
|
||
contents: write
|
||
|
||
jobs:
|
||
screenshots:
|
||
name: Capture Landing Page Screenshots
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- uses: pnpm/action-setup@v4
|
||
with:
|
||
version: latest
|
||
|
||
- uses: actions/setup-node@v4
|
||
with:
|
||
node-version: 22
|
||
cache: pnpm
|
||
|
||
- run: pnpm install --frozen-lockfile
|
||
|
||
- name: Install Playwright browsers and system deps
|
||
run: pnpm exec playwright install --with-deps chromium
|
||
|
||
- name: Build app
|
||
run: pnpm build
|
||
env:
|
||
DATABASE_URL: ./data/screenshots.db
|
||
|
||
- name: Capture screenshots
|
||
run: pnpm exec tsx scripts/screenshots.ts
|
||
env:
|
||
DATABASE_URL: ./data/screenshots.db
|
||
|
||
- name: Commit screenshots
|
||
run: |
|
||
git config user.name "github-actions[bot]"
|
||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||
git add website/assets/screenshot-*.png
|
||
git diff --cached --quiet && echo "No screenshot changes" && exit 0
|
||
git commit -m "chore: update landing page screenshots [skip ci]"
|
||
git push origin main
|
||
```
|
||
|
||
## Script Structure
|
||
|
||
```typescript
|
||
// scripts/screenshots.ts
|
||
|
||
import { chromium, type Page } from 'playwright';
|
||
import { spawn, type ChildProcess } from 'child_process';
|
||
import { generateBretzelPixelArt } from './fixtures/bretzel-pixel';
|
||
|
||
const BASE = 'http://localhost:4173';
|
||
const DESKTOP = { width: 1280, height: 800 };
|
||
const MOBILE = { width: 390, height: 844 };
|
||
const OUTPUT = 'website/assets';
|
||
|
||
async function main() {
|
||
// 1. Start preview server (spawn child process, wait for port 4173)
|
||
const server = await startPreviewServer();
|
||
|
||
// 2. Launch browser
|
||
const browser = await chromium.launch();
|
||
|
||
try {
|
||
// 3. Seed data (desktop context — API calls work at any viewport)
|
||
const seedContext = await browser.newContext({ viewport: DESKTOP });
|
||
const seedPage = await seedContext.newPage();
|
||
await seed(seedPage);
|
||
|
||
// 4. Desktop screenshots
|
||
await captureDesktop(seedPage);
|
||
await seedContext.close();
|
||
|
||
// 5. Mobile screenshots
|
||
const mobileContext = await browser.newContext({ viewport: MOBILE });
|
||
const mobilePage = await mobileContext.newPage();
|
||
await login(mobilePage);
|
||
await captureMobile(mobilePage);
|
||
await mobileContext.close();
|
||
} finally {
|
||
await browser.close();
|
||
server.close();
|
||
}
|
||
}
|
||
|
||
async function seed(page: Page) {
|
||
// Setup admin via POST /api/auth/setup
|
||
// Login via POST /api/auth/login (sets session cookie on page context)
|
||
// Create notes via POST /api/notes (with content, color, tags:string[], pinned, checklistMode)
|
||
// → capture note IDs from responses for later use
|
||
// Create collaborator user via POST /api/admin/users
|
||
// → capture alice.id (numeric) from response
|
||
// Share a note via POST /api/notes/:id/collaborators { userId: alice.id }
|
||
// Create version history: PATCH /api/notes/:id × 4-5 with varying content
|
||
// Upload pixel-art bretzel image via POST /api/notes/:id/attachments (multipart form)
|
||
// Create API keys via POST /api/settings/api-keys { name: "Claude Code" } and { name: "N8N" }
|
||
}
|
||
|
||
async function captureDesktop(page: Page) {
|
||
// D1: Grid view
|
||
// D2: Editor (Self-Hosting Stack)
|
||
// D3: Checklist (Bretzel Ingredients)
|
||
// D4: Sharing dialog
|
||
// D5: Version history
|
||
// D6: Attachments
|
||
// D7: API/MCP settings
|
||
}
|
||
|
||
async function captureMobile(page: Page) {
|
||
// M1: Grid view
|
||
// M2: Editor
|
||
// M3: Checklist
|
||
}
|
||
```
|
||
|
||
## Landing Page Updates
|
||
|
||
After the screenshots are generated, `website/index.html` needs updating:
|
||
- Add new screenshot entries for: checklist, sharing, history, attachments, API
|
||
- Update alt text and labels
|
||
- Hero image stays as `screenshot-grid.png`
|
||
- Mobile section adds checklist screenshot, replaces sidebar screenshot
|
||
|
||
## Dependencies
|
||
|
||
No new dependencies. Uses:
|
||
- `playwright` (already in devDependencies for e2e tests)
|
||
- `tsx` (already in devDependencies for other scripts)
|
||
- Node.js built-in `fs`, `path`, `Buffer` for pixel-art PNG generation
|
||
- SvelteKit's preview server (spawned as child process via `pnpm preview`)
|
||
|
||
## Open Questions
|
||
|
||
None — all decisions resolved during brainstorming.
|