Skip to main content
vibld

Template

Dani Okafor

A bold portrait photographer's portfolio whose home page is an accordion-style carousel of tall rounded portrait panels: one expanded with a caption, the rest as narrow slivers. Navigation leads to themed collections (portraits, candid life, people and passions) and an about page, with contact details always visible.

Portrait photographer portfolio · 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.

Account setup
Add edit
Analytics
Appearance
Calendar
Chat
Checklist
Checkout
Confirmation
Dashboard
Delete account
Details
Discovery questions
Empty state
Flowchart
Import export
Inbox
Integrations
Invite team
Loading
Login
Onboarding
Plans
Playground
Product tour
Referral
Search
Settings
Share
Sign up
Success
Table
Team members
Text editor
Upgrade
Usage
Verification
Welcome

Start from this templateRead the build prompt

Typefaces

The warm, friendly single geometric family is the design, and Poppins stays in only a few templates.

  • PoppinsHeadings: name ~38px bold at -0.96px
  • PoppinsBody: nav and contact 16-18px

Who it is for

  • Portrait photographers with a distinct voice
  • Photographers seeking brand collaborations
  • Artists submitting thematic collections
  • Clients booking portrait sessions

Layout

  1. Header: bold name top-left, collection links below (Portraits, Everyday, People & Craft, About); email and phone right-aligned
  2. Horizontal row of tall rounded portrait panels; the active one expands wide with a caption (name - role - year), others compressed into slivers
  3. Collection pages with gallery layouts and lightbox
  4. About page

Palette

Warm, human, vibrant, friendly, dynamic. It celebrates faces and personalities.

  • background#fcfaf8
  • text#2e251f
  • primary#3d3129
  • accent terracotta (fills, large text)#dd713c
  • terracotta text / links#b2501f
  • secondary#f2f0ed
  • decorative border#e5e0dc
  • nav gray / muted text#6f6760
  • caption scrim (black 60%)#00000099

Every checked pair, measured again

SampleWhereRatioNeeds
Aabody text on background14.40:14.5:1
Aatext on secondary13.18:14.5:1
Aanav gray on background5.33:14.5:1
Aanav gray on secondary4.88:14.5:1
Aaterracotta link text on background4.97:14.5:1
Aaterracotta link text on secondary4.55:14.5:1
terracotta 24px+ accent / indicator on background3.10:13:1
Aawhite text on primary button12.58:14.5:1
Aacaption over 60% black scrim on white-worst-case photo5.74:14.5:1
focus ring (primary) on background12.08:13: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
Poppins bold, ~38px with -0.96px tracking for the name
Body
Poppins 16-18px regular for nav and contact

Single geometric family, friendly and approachable; hierarchy by weight

Spacing and imagery

40px margins; portrait panels ~480px tall with 20px gaps and ~24px corner radius; single-screen home

Close-up color and black-and-white studio portraits of diverse people with soft backgrounds, cropped into tall rounded panels

Components

  • Name + collection nav header
  • Contact info block
  • Expanding portrait panel carousel
  • Caption overlay
  • Collection gallery
  • Lightbox (LightGallery)
  • Swiper slider
  • About section
  • Scroll-triggered animations

Interactions

  • Hover/click expands a panel while others compress (flex-grow animation)
  • Auto-advance with pause on hover
  • Swipe on touch
  • Caption fades in on active panel
  • GSAP scroll-triggered reveals on collection pages
  • Lightbox zoom and navigation

Data

  • Portrait{src, alt, subject, role, year, collection}
  • Collection{slug, title, description, cover}
  • Contact{email, phone}

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 portfolio for a fictional portrait photographer called **Dani Okafor**. The audience is people booking portrait sessions, brands looking for a photographer with a warm human style, and galleries reviewing themed series. The home page is a single, lively screen: a row of tall rounded portrait panels where one expands to show a caption while the others shrink to slivers.

### Stack
React 18 + TypeScript + Vite, Tailwind CSS, shadcn/ui (Radix Dialog), lucide-react, React Router, Framer Motion for the panel expansion (`layout` animations), Swiper for touch galleries on collection pages, and a lightbox built from Radix Dialog (or yet-another-react-lightbox). GSAP is optional for scroll reveals. No backend.

### Pages & layout
1. Header: the photographer's name in bold at top left, with collection links underneath (Portraits, Everyday, People & Craft, About); email and phone right-aligned as plain links.
2. Home: a full-width row of 6–8 tall panels (about 480px) with 20px gaps and large corner radius. The active panel grows to about 3× width and shows a caption (subject – role – year) bottom-right; the others compress. It advances every 5s and pauses on hover or focus.
3. Collection page: intro line and a responsive gallery (masonry or justified) opening a lightbox with captions.
4. About: portrait of the photographer, bio, services (sessions, editorial, brand), and booking info.

### Design system
Tokens: `--background: #fcfaf8; --foreground: #2e251f; --primary: #3d3129; --accent: #dd713c; --secondary: #f2f0ed; --border: #e5e0dc; --muted-foreground: #6f6760; --accent-text: #b2501f; --border: decorative only`. Font: Poppins 400/500/700. Scale: 38px name with -2.5% tracking; 18px nav; 16px body at line-height 1.6, max 70ch; 13px captions at weight 500. Radius: 24px panels, 12px gallery images. Spacing: 40px margins, 20px panel gap. Motion: 500ms `cubic-bezier(.22,1,.36,1)` flex-grow transitions; 300ms caption fade. Light only.

### Components & interactions
- Panel strip: each panel is a button; hover, focus or tap expands it; left/right arrow keys move the active panel; autoplay has a visible pause/play button.
- Caption: white text that fades in on the active panel over a bottom gradient reaching 60% black.
- Gallery: lazy images with blurred placeholders; the lightbox supports arrows, swipe, Esc, and returns focus.
- Mobile: the strip becomes a horizontal snap carousel with one active card and peeking neighbors.
- Error fallback tile for failed images; empty collection message.

### Data & state
`Portrait{src,alt,subject,role,year,collection}`, `Collection{slug,title,description,cover}`, `Contact{email,phone}`. Active index state lives in the strip component; the lightbox index is in the URL. Use fictional subject names and roles, with consent-friendly stock or generated faces.

### Accessibility
The nav gray is #6f6760 on #fcfaf8 (5.3:1). Caption text sits on a bottom gradient reaching 60% black, which holds white captions at 5.7:1 over any portrait. The terracotta #dd713c is only 3.1:1 on the background, so it is used for fills and 24px+ text; small terracotta text and links use #b2501f. Autoplay must be pausable (WCAG 2.2.2) and off under `prefers-reduced-motion`. Panels need accessible names ("Portrait of Alex, music teacher, 2024") and `aria-expanded` or `aria-current` on the active one. Phone and email should be real `tel:` and `mailto:` links. Verified contrast: body text on background: #2e251f on #fcfaf8 = 14.4:1; nav gray on background: #6f6760 on #fcfaf8 = 5.33:1; terracotta link text on background: #b2501f on #fcfaf8 = 4.97:1; caption over 60% black scrim on white-worst-case photo: #ffffff on #666666 = 5.74:1.

### Security
Static: no forms required; if booking is added, validate with zod on the client and server with a honeypot. Strip EXIF metadata from images. External links use `rel="noopener noreferrer"`. Don't publish a personal mobile number in demo data; use a clearly fake placeholder.

### Performance & SEO
Only the visible panels load at full size; others use smaller crops (they're slivers). Serve AVIF/WebP with `srcset`; lazy-load collection images; code-split the lightbox. Person and ImageGallery JSON-LD; per-collection meta and OG images.

### Guardrails
- Use licensed or generated portraits with fictional names and roles; never caption real people with made-up biographies.
- No fake testimonials.
- Collect no personal data.
- Keep components small and typed, never use `any`, and show failed images visibly.
- Done when: the strip expands smoothly by mouse, keyboard and touch; autoplay pauses via control and reduced motion; captions meet contrast; collections open a working lightbox; the home page has no layout shift during expansion.

Open the builderAll templatesThis palette on its own