Template
Linnea Farrow
A stark, typographic portfolio for a nature and landscape photographer. A five-column top nav holds the name, category links (Landscape, Nature, Animals) and Info, and above a footer with studio address and contact it presents category galleries in a lightbox-driven layout. It helps photographers book clients, sell prints and pitch editorial projects.
Typographic nature photographer site · Website · Portfolio · static site
A mock-up of the homepage, drawn from this design’s layout, palette and typefaces. A build follows the full prompt below.
Start from this templateRead the build prompt
Typefaces
Sen is a small, clean geometric sans close to Satoshi that stays tiny and bold in the nav, leaving the white wall to the photographs.
- SenHeadings: nav and name 18px 700
- SenBody: body ~19.5px regular
Who it is for
- Landscape and wildlife photographers
- Photographers selling fine art prints
- Editorial and documentary shooters pitching projects
- Artists with a consistent visual style
Layout
- Top nav spread across five equal columns: name, Landscape, Nature, Animals, Info in bold sans
- Category gallery sections: large images per category, opened in a lightbox
- Pricing / print sizes section
- Booking inquiry form with validation and file upload
- Footer: name, studio address, email, Instagram, copyright
- Info page with bio and contact
Palette
Stark, minimal, confident, gallery-white, understated. The page is a blank white wall waiting for large nature photographs.
- background
#ffffff - text
#000000 - primary
#000000 - muted
#f5f5f5 - border
#ededed - secondary text
#6b6b6b - input border
#6b6b6b
Every checked pair, measured again
| Sample | Where | Ratio | Needs |
|---|---|---|---|
| Aa | body and nav text on white | 21.00:1 | 4.5:1 |
| Aa | captions and muted text on white | 5.33:1 | 4.5:1 |
| Aa | muted text on muted surface | 4.89:1 | 4.5:1 |
| Aa | primary button text on black | 21.00:1 | 4.5:1 |
| input border on white | 5.33:1 | 3:1 | |
| focus ring on white | 21.00:1 | 3:1 | |
| Aa | lightbox caption on black backdrop | 21.00:1 | 4.5:1 |
As vibld’s tokens
The palette on the fifteen colour tokens vibld styles a project with, each text colour on the fill it is read on. Marked tokens are solved from the palette, because no swatch held that role at 4.5:1.
- background
- card
- muted
- primary
- secondary
- accent
- destructive *
Type scale
- Display
- Satoshi 700, 18px for nav and name, no tracking (Satoshi is not on Google Fonts; a vibld project loads Sen)
- Body
- Satoshi ~19.5px regular (Satoshi is not on Google Fonts; a vibld project loads Sen)
A single geometric sans in bold small sizes; the typography stays tiny so photographs dominate.
Spacing and imagery
Wide 48px margins, nav spread edge to edge in equal columns, zero radius, black-on-white with no decoration.
Landscape, nature and animal photography, shown full-width and uncropped, opened in a lightbox.
Components
- Five-column text nav
- Category filter links
- Gallery sections per category
- Lightbox (LightGallery-style)
- Smooth-scroll container
- Print pricing table
- Booking inquiry form with file upload
- Footer with address and contact
- Info page
- Skip link
Interactions
- Category links jump or filter to the matching gallery
- Images open in a lightbox with zoom, thumbnails, keyboard and swipe
- Smooth inertial scrolling (Locomotive-style) with GSAP reveals
- Lazy-loaded images fade in
- Inquiry form validates and accepts reference image uploads
- Hover underline on nav links
Data
Photo{id, src, alt, category, title, year, printable}Category{slug, title}PrintOption{size, paper, price}Inquiry{name, email, type, date?, message, attachments[]}
Build prompt
The baseline every prompt in the catalog assumes, then this design’s own ten sections, from goal to guardrails.
The baseline
### How to use these prompts Paste a template's build prompt into your coding agent as the first message. Each prompt names its own stack, tokens and acceptance criteria; the rules below apply to all of them and can be prepended once per project. ### Engineering baseline - TypeScript strict mode, no `any`, small typed components, feature folders, and one source of truth for design tokens (CSS variables consumed by Tailwind). - Validate every input with a shared zod schema on the client and again on the server or edge function. Never trust client-side checks alone. - Show loading, empty and error states for every async view. Surface errors in plain language with a retry, and log details to the console in development only. - Keep secrets out of the bundle. Only publishable keys (for example a Supabase anon key) belong in client code; service-role keys, API keys and webhooks live in server or edge-function environment variables. ### Data and auth baseline (full-stack templates) - Enable Row Level Security on every table before inserting data. Default-deny, then add owner-scoped policies (`auth.uid() = user_id`) and explicit role checks for admin views. - Store roles in a separate table checked by a security-definer function, never in a user-editable profile field. - Upload files to private storage buckets with size and MIME limits, and serve them through signed URLs. - Rate-limit public endpoints (forms, auth, AI calls) and add a honeypot field or captcha to anonymous forms. - Take payments through a hosted checkout and verify webhooks by signature. Never handle raw card data. ### Accessibility and UX baseline - Target WCAG 2.2 AA: 4.5:1 contrast for normal text and 3:1 for large text, input borders, focus rings and meaningful icons or chart lines. Every palette in this catalog lists its verified pairs; re-check with a contrast tool after any colour change. - Keep body text at 16px or larger with 1.5 line height, nothing below 12px, no light weights under 24px, and uppercase only for short labels. - Give every interactive element a visible focus ring, full keyboard support, semantic landmarks, labelled form fields, and alt text on meaningful images. - Respect `prefers-reduced-motion` for every animation. Give drag-and-drop and carousels keyboard and button alternatives. - Build mobile-first and test at 375px, 768px and 1280px. ### Content guardrails - Use original copy, fictional sample data and placeholder or licensed imagery. Do not reuse another product's name, logo, screenshots or marketing text. - Label demo testimonials and metrics as samples. Collect the minimum personal data the feature needs.
### Goal
Build a gallery-white portfolio for a fictional nature photographer, "Linnea Farrow". It serves three audiences: clients booking commissions, collectors buying prints and editors reviewing projects. The design is almost pure typography. A spare, bold nav names the categories, and each category opens into large photographs viewable in a lightbox. A print-pricing section and a booking form turn interest into inquiries.
### Stack
React 18 + TypeScript + Vite, Tailwind CSS, shadcn/ui (Radix Form, Select, Table, Toast) and lucide-react. Use LightGallery (or yet-another-react-lightbox) for zoom and thumbnails, GSAP ScrollTrigger for gentle reveals, Lenis (a lighter alternative to Locomotive Scroll) for smooth scrolling and react-hook-form + zod. The only backend is a small serverless or Supabase Edge Function that accepts inquiries plus optional reference images, stored in a private Storage bucket.
### Pages & layout
1. Nav: a 5-column grid spanning the page, with the name in column 1 and Landscape, Nature, Animals and Info in the others. Bold 18px text; the active category is underlined.
2. Category view: a 2-column grid on desktop (1 on mobile) of large images at natural ratios with a 48px gap and small captions (title, year).
3. Prints: a table of sizes, papers and prices (from a config), with a "Request this print" link that pre-fills the form.
4. Booking: name, email, inquiry type (commission / print / editorial), preferred date (optional), message and up to three reference images.
5. Footer: name, studio address (placeholder), email, Instagram and copyright, laid out on the same 5-column grid.
### Design system
- `--background: #ffffff`, `--foreground: #000000`, `--muted: #f5f5f5`, `--border: #ededed`, `--muted-foreground: #6b6b6b`, `--input-border: #6b6b6b` (the #ededed border is decorative only), `--radius: 0`.
- Font: Satoshi (Fontshare) or General Sans at 400/700. Scale: 14 / 18 / 20 / 32px. Bold is for navigation only; body is 18-20px at 1.6 line-height with a ~70ch measure.
- Spacing: 8px base, 48px page margins, 96px between sections. No shadows.
- Motion: Lenis smoothing with lerp 0.1, 600ms image fade-ins and 250ms lightbox transitions. Light only.
- Typeface: Sen (Google Fonts) for nav and name 18px 700.
### Components & interactions
- CategoryNav: links with `aria-current` and a hover underline.
- GalleryImage: blur placeholder, then fade in. Click or Enter opens the lightbox at that index. Show an error tile if loading fails.
- Lightbox: zoom, thumbnails, keyboard, swipe and a caption. Focus returns on close.
- InquiryForm: states for invalid, uploading (progress), submitting, success and error. Selecting "Print" shows the size select.
- Empty category: "New work coming soon."
### Data & state
Typed JSON: `Photo{id, src, alt, category, title, year, printable}`, `PrintOption{size, paper, price}` and `Category`. The active category lives in the URL. Inquiries go to the function, and attachments go to private storage via short-lived signed upload URLs. Seed 10-15 placeholder photos per category.
### Accessibility
- Smooth-scroll libraries must not break keyboard scrolling, anchor links or screen readers. Disable Lenis under reduced motion.
- Every photo has alt text. The pricing table uses `<th scope>`.
- Form fields have visible labels, errors are announced and the file input has an accessible name and constraints text.
- Verified contrast: body #000000 on #ffffff = 21.0:1; muted #6b6b6b on #ffffff = 5.33:1; muted on surface #6b6b6b on #f5f5f5 = 4.89:1; input border #6b6b6b on #ffffff = 5.33:1.
### Security
- zod validation in the client and in the function. Allow only JPEG/PNG/WebP up to 5MB each, max 3, checked by MIME and size on the server.
- Storage bucket is private, with no public file browsing and signed URLs only. Add a honeypot and per-IP rate limit.
- The service key stays in function env. Never take payments on-site; link to a hosted checkout if prints are sold.
### Performance & SEO
Serve `srcset` AVIF/WebP and lazy-load all images below the fold. Code-split the lightbox. Add ImageGallery and LocalBusiness JSON-LD and per-category titles and OG images.
### Guardrails
- Do write all copy yourself and use placeholder imagery (Unsplash-style stock or generated); no trademarked names, client logos or real people.
- Don't present invented testimonials or awards as real; label sample content as sample.
- Keep components small and fully typed; no `any`. Surface errors visibly instead of failing silently.
- Don't collect or store more personal data than the contact form needs.
- Done when:
- [ ] Category nav switches galleries and updates the URL
- [ ] Lightbox supports zoom, keys, swipe and focus return
- [ ] Inquiry form enforces type/size limits client- and server-side
- [ ] Smooth scroll is disabled under reduced-motion
- [ ] Pricing table is semantic and readable on mobile