Skip to main content
vibld

Template

Solenne Marsh

A clean, image-first website for an editorial and commercial photographer. A full-viewport hero with widely tracked light-weight name type leads into an about section, a grid of featured projects with hover previews and a lightbox, and a validated contact form. It is designed to help a photographer launch or prove an independent business.

Editorial photographer website · 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

Lexend Exa is drawn wide and has ultralight weights, so the widely spaced photographer's-signature caps come naturally.

  • Lexend ExaHeadings: display 128px at 200 uppercase, 0.1em; headings 36px 300
  • Lexend ExaBody: UI and body 16px, 400/500

Who it is for

  • Photographers launching an independent business
  • Editorial and commercial shooters
  • Small studios presenting several services
  • Creatives who need dark mode and a lightbox

Layout

  1. Transparent top nav over hero: name left; Home, Portfolio, About, Contact and a theme toggle right; becomes solid white with blur on scroll
  2. Full-viewport hero: soft gray gradient/photo, huge thin uppercase name with wide tracking, role subtitle, one-line tagline, 'Scroll' cue with chevron
  3. About My Work: centered heading and biography paragraph
  4. Featured Projects: two-column grid of large rounded image cards (e.g. landscape, street, architecture, fashion)
  5. Lightbox overlay for full-screen viewing
  6. Contact section with validated form
  7. Footer with social links

Palette

Clean, airy, modern, quiet, professional. It is a white-gallery feel where the photos supply all the color.

  • background#ffffff
  • text#09090b
  • primary#18181b
  • muted surface#f4f4f5
  • border#e4e4e7
  • hero overlay gray#9a9a9a

Every checked pair, measured again

SampleWhereRatioNeeds
Aabody text on background19.90:14.5:1
Aamuted text on background4.83:14.5:1
Aaprimary button text on primary17.72:14.5:1
input border on background4.83:13:1
focus ring on background17.72:13:1
Aawhite hero text on 45% black overlay over gray backdrop7.46:14.5:1
Aawhite card caption on 60% black scrim5.74:14.5:1
Aadark mode body text19.06:14.5:1
Aadark mode muted text7.76:14.5:1
Aadark mode primary button text16.97:14.5:1
dark mode focus ring on background19.06:13:1
dark mode input border4.12:13: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
System sans at weight 200, 128px, uppercase, 0.1em tracking (12.8px) (the system face is not on Google Fonts; a vibld project loads Lexend Exa)
Body
System sans 16px regular; section headings 36px weight 300 with slight tracking (the system face is not on Google Fonts; a vibld project loads Lexend Exa)

Ultra-light, widely spaced caps feel like a photographer's signature; a neutral sans keeps attention on photos.

Spacing and imagery

Full-bleed hero, then a centered container with 16px gaps between image cards; generous 96px section padding; cards have small radius (~6px).

Full-color landscape, street, architectural and fashion photography in large 3:2 cards; hero uses a desaturated gray gradient backdrop.

Components

  • Scroll-aware transparent-to-solid navbar
  • Active nav underline
  • Light/dark theme toggle
  • Full-screen typographic hero
  • Scroll cue with bouncing chevron
  • About section
  • Featured project grid
  • Hover project preview (zoom + caption)
  • Lightbox with swipe and keyboard
  • Contact form with validation
  • Social footer
  • Mobile menu sheet

Interactions

  • Navbar gains background and blur after scrolling past hero
  • Project cards zoom slightly and reveal title/category on hover
  • Lightbox opens with fade, supports arrow keys, Esc and swipe
  • Theme toggle switches light/dark with persisted preference
  • Contact form inline errors and toast on submit
  • Scroll cue chevron bounces; smooth scroll to sections

Data

  • Project{id, title, category, cover, images[], description}
  • Photo{src, alt, width, height}
  • ContactMessage{name, email, shootType, message}

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 minimal photographer website for a fictional editorial and commercial photographer, "Solenne Marsh". Its audience is art buyers, editors and private clients who want to see the work quickly and then make contact. It needs a typographic hero, a short bio, a grid of featured series that open in a full-screen lightbox, and a contact form.

### Stack
React 18 + TypeScript + Vite, Tailwind CSS with `darkMode: 'class'`, shadcn/ui (Radix) for Dialog, Sheet, Form, Toast and Button, and lucide-react. Use Embla Carousel inside the lightbox for swipe, Framer Motion for fades, and react-hook-form + zod for the form. No database is needed; send messages through a serverless function.

### Pages & layout
1. Navbar: the name in spaced caps on the left and links plus a sun/moon toggle on the right. It starts transparent over the hero, then turns white/80 with a backdrop blur and hairline border after 80px of scroll. On mobile, the links collapse into a Sheet.
2. Hero at 100vh: a soft neutral gradient or a muted photo, the name at 96-128px weight 200 (48px/300 minimum on mobile) with 0.1em tracking, a role line, a one-line tagline and "Scroll" with a chevron.
3. About: centered heading and short bio (640px column).
4. Featured Projects: a two-column grid (one column on mobile) of 3:2 cards with 6px radius and a 16px gap. Each card opens that series in the lightbox.
5. Contact: name, email, shoot type (select) and message.
6. Footer: name, social icons, copyright.

### Design system
- Light: `--background: 0 0% 100%`, `--foreground: 240 10% 4%`, `--primary: 240 6% 10%`, `--muted: 240 5% 96%`, `--border: 240 6% 90%` (decorative), `--muted-foreground`/`--input-border: 240 4% 46%`, `--ring: 240 6% 10%`.
- Dark: background 240 10% 4%; foreground, ring and primary 0 0% 98%; muted-foreground 240 5% 65%.
- Fonts: Lexend Exa from Google Fonts, 200 for display and 300 for headings, with 400/500 for UI. Scale: 12 / 14 / 16 / 20 / 36 / 64 / 128px. Body 16px/1.6.
- Spacing: 4px base, 96px sections; radius 6px.
- Motion: 300ms ease-out for fades, 500ms for image zoom, and 1.6s infinite bounce on the chevron.

### Components & interactions
- Navbar: states for transparent, scrolled and mobile-open. The active link gets an underline.
- ProjectCard: on hover, the image scales 1.05 and a caption on a black 60% gradient scrim (effective #666666 or darker) shows the title and category. The same happens on focus. Show a blurred placeholder while loading.
- Lightbox: Dialog plus carousel with previous/next buttons, arrow keys, Esc to close, swipe on touch and a counter such as "3 / 12". Return focus on close.
- ThemeToggle: defaults to system, persists in localStorage.
- ContactForm: states for idle, invalid (inline messages), submitting (disabled button with spinner), success (toast and reset) and error (toast with retry).

### Data & state
Store a typed `projects` array: `{id, title, category, cover, images: {src, alt, w, h}[], description}`. Lightbox state (open series, index) lives in a small context. The theme is kept in context and localStorage. Seed four fictional series with placeholder photos.

### Accessibility
- White hero text sits on a black 45% overlay (effective #555555 over the gray backdrop, 7.46:1).
- The lightbox is a labelled modal dialog that traps focus, and every slide has alt text.
- The toggle has `aria-pressed` and a label. Focus rings are 2px `--ring` with an offset, visible in both themes.
- Disable zoom and bounce under reduced-motion.
- Verified contrast: body #09090b on #ffffff = 19.9:1; muted #71717a on #ffffff = 4.83:1; button #ffffff on #18181b = 17.72:1.

### Security
- zod validation on the client and in the function. Add a honeypot, a rate limit and a max length of 2,000 characters for the message.
- No API keys in client-side code.
- External links use `rel="noopener noreferrer"`.

### Performance & SEO
Use responsive `srcset` with width/height attributes, lazy-loading and blur-up placeholders. Preload only the hero asset. Add Photographer/LocalBusiness JSON-LD, OG images from a cover and descriptive titles.

### 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:
  - [ ] Navbar transitions from transparent to solid on scroll and works as a mobile sheet
  - [ ] Lightbox supports keyboard, swipe and focus return
  - [ ] Dark mode persists across reloads
  - [ ] Contact form covers invalid, submitting, success and error states
  - [ ] Images lazy-load without layout shift

Open the builderAll templatesThis palette on its own