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.
Add app screens
Pick up to 6 screens, such as a dashboard, settings or an empty state. Each is built in this design’s own palette and typefaces, with its states and guardrails.
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
- Transparent top nav over hero: name left; Home, Portfolio, About, Contact and a theme toggle right; becomes solid white with blur on scroll
- Full-viewport hero: soft gray gradient/photo, huge thin uppercase name with wide tracking, role subtitle, one-line tagline, 'Scroll' cue with chevron
- About My Work: centered heading and biography paragraph
- Featured Projects: two-column grid of large rounded image cards (e.g. landscape, street, architecture, fashion)
- Lightbox overlay for full-screen viewing
- Contact section with validated form
- 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
| Sample | Where | Ratio | Needs |
|---|---|---|---|
| Aa | body text on background | 19.90:1 | 4.5:1 |
| Aa | muted text on background | 4.83:1 | 4.5:1 |
| Aa | primary button text on primary | 17.72:1 | 4.5:1 |
| input border on background | 4.83:1 | 3:1 | |
| focus ring on background | 17.72:1 | 3:1 | |
| Aa | white hero text on 45% black overlay over gray backdrop | 7.46:1 | 4.5:1 |
| Aa | white card caption on 60% black scrim | 5.74:1 | 4.5:1 |
| Aa | dark mode body text | 19.06:1 | 4.5:1 |
| Aa | dark mode muted text | 7.76:1 | 4.5:1 |
| Aa | dark mode primary button text | 16.97:1 | 4.5:1 |
| dark mode focus ring on background | 19.06:1 | 3:1 | |
| dark mode input border | 4.12:1 | 3:1 |
As vibld’s tokens
The palette on the 15+ color tokens vibld styles a project with, each text color 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 color 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, labeled 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 labeled 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