Skip to main content
vibld

Template

Transom

A horizontally scrolling, monospace-typed photography portfolio. A compact three-column text header holds the name and project links, a short sentence-case artist statement, and about/email/social links. Below it, a snap-scrolling row of large photographs carries a floating client caption that updates per slide. It targets photographers who want a fast, editorial, premium-feeling site.

Horizontal-scroll monospace photo 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

PT Mono is a crisp single-weight mono, which matches the design's 400-only rule, and Courier Prime stays as the named typewriter alternative for the index-card feel.

  • PT MonoHeadings: statement 16-18px regular, uppercase short labels
  • PT MonoBody: paragraphs 16px/1.5, 12px marquee
  • Courier PrimeAccent: the named typewriter alternative

Who it is for

  • Architectural and lifestyle photographers
  • Photographers pitching for premium bookings
  • Agencies customizing sites for several shooters
  • Creatives who favor typewriter-style minimalism

Layout

  1. Three-column text header: name + Project 1 / Project 2 links left; sentence-case artist statement center; About, Email, Instagram right
  2. Full-width horizontal snap gallery of tall images at varied widths with a small gap
  3. Floating label on the current slide ('For [client]') with a white/glass background
  4. Infinite client marquee
  5. About page with bio and contact

Palette

Crisp, editorial, typewritten, sunny, efficient. It feels like an index card taped next to large prints.

  • background#ffffff
  • text#09090b
  • primary#18181b
  • muted#f4f4f5
  • border#e4e4e7
  • photo accent (turquoise)#5ec8d8
  • meta text#71717a

Every checked pair, measured again

SampleWhereRatioNeeds
Aatext on white19.90:14.5:1
Aaslide caption on white/85 glass over darkest photo14.09:14.5:1
Aaprimary button text17.72:14.5:1
Aatext on muted surface18.10:14.5:1
Aasecondary/meta text on white4.83:14.5:1
prev/next button outline and focus ring17.72:13:1
focus ring over caption glass12.55: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
Monospace (IBM Plex Mono-like) 16-18px regular; uppercase with 0.06em tracking only for short labels (Monospace is not on Google Fonts; a vibld project loads PT Mono)
Body
Same monospace in sentence case at 1.5 line-height (Monospace is not on Google Fonts; a vibld project loads PT Mono)

One monospaced face with small capitalized labels keeps the page like a typed contact sheet; photos provide all the scale.

Spacing and imagery

24px page margin, 12px gap between slides, images ~670px tall filling the viewport below the header; no radius.

Bright, saturated architectural details (colored doors, balconies, facades) as tall, uncropped verticals and wide horizontals.

Components

  • Three-column text header
  • Project links
  • Artist statement block
  • Horizontal snap gallery
  • Floating slide caption with glass backdrop
  • Client marquee
  • About page
  • Email and Instagram links
  • Toast on copy-email

Interactions

  • Horizontal scroll with snap; vertical wheel mapped to horizontal
  • Caption text updates to the client of the slide in view
  • Staggered slide-in entrance animation (React Spring)
  • Marquee scrolls infinitely, pauses on hover
  • Arrow keys move one slide
  • Copy-email button shows a toast

Data

  • Project{slug, title, slides: Slide[]}
  • Slide{src, alt, width, height, client}
  • Client{name}
  • site.json for all content

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 lightweight, typewriter-style photography portfolio for a fictional architecture and lifestyle photographer, "Transom". Its audience is art directors and brands booking shoots. The home view is a single horizontal strip of big images that snaps slide by slide, with a floating caption naming the (fictional) client for each frame. A dense monospace header holds all navigation and a short statement. Keep the JavaScript payload tiny.

### Stack
React 18 + TypeScript + Vite, Tailwind CSS, shadcn/ui (only Button and Toast via Sonner) and lucide-react. Use React Spring for staggered entrances and caption transitions and React Router for `/`, `/project/:slug` and `/about`. Content comes from a typed `site.json`. No backend. Keep the JavaScript payload under 250KB gzipped.

### Pages & layout
1. Header: a 3-column grid (3/6/3 of 12) set in mono at 16px (labels uppercase, statement sentence case). Left: name, then project links. Center: a 2-3 line statement. Right: About, Email and Instagram.
2. Gallery: a `scroll-snap-type: x mandatory` row filling the remaining viewport height with 12px gaps. Each slide keeps its image ratio at fixed height.
3. Caption: pinned top-left over the active slide, "FOR [CLIENT]", on a white/85 background with `backdrop-blur` (effective #d9d9d9 or lighter even over black imagery).
4. Client marquee near the bottom or on the About page.
5. About: a portrait, a short bio, services and contact.
6. Mobile: the header stacks and the gallery becomes a vertical list, since horizontal swipe is optional.

### Design system
- `--background: #ffffff`, `--foreground: #09090b`, `--primary: #18181b`, `--muted: #f4f4f5`, `--border: #e4e4e7`.
- Font: PT Mono (Courier Prime as an alternative) from Google Fonts, 400 only, 16px/1.5. Uppercase with 0.06em tracking is reserved for short labels (nav links, the slide caption, marquee names); the statement and all paragraphs are sentence case. The only other size is 12px for the marquee.
- Spacing: 4px base; 24px page margin; 12px gallery gap. Radius 0.
- Motion: spring (tension 210, friction 20) with an 80ms stagger per slide; 200ms caption crossfade. Light only.

### Components & interactions
- HorizontalGallery: converts vertical wheel to horizontal scroll (not on trackpads that already scroll horizontally) and supports ←/→ keys. Uses IntersectionObserver to set the active slide.
- SlideCaption: animates text changes. Show a gray shimmer while an image loads, and a caption-only tile on error.
- EmailLink: a `mailto:` plus a copy button that shows a Sonner toast ("Email copied").
- Marquee: pauses on hover or focus and is static under reduced motion.

### Data & state
`site.json` has `{ name, statement, links, projects: Project{slug, title, slides: Slide{src, alt, w, h, client}[]}[], clients: string[] }`. Parse it with zod and render a readable error panel if it is invalid. State is the active slide index. Seed two projects of 8-10 placeholder images with invented client names.

### Accessibility
- Build the gallery as a labeled region (`role="region" aria-label="Project 1 gallery"`) that is focusable and keyboard-scrollable, with visible prev/next buttons for pointer users who cannot scroll sideways.
- The caption is text, not baked into the image. Every image has alt text.
- Uppercase is limited to labels of four words or fewer with 0.06em tracking; the statement and About copy stay in sentence case.
- Respect reduced motion.
- Verified contrast: text #09090b on #ffffff = 19.9:1; caption #09090b on #d9d9d9 = 14.09:1; button #ffffff on #18181b = 17.72:1; meta #71717a on #ffffff = 4.83:1.

### Security
- No forms. `mailto:` only.
- External links use `rel="noopener noreferrer"`.
- JSON validated at build time. No secrets in client-side code.

### Performance & SEO
Eager-load only the first two slides and lazy-load the rest with explicit dimensions. Use AVIF/WebP with `srcset` keyed to the viewport height. Add per-project titles and OG images and a meaningful H1 (visually hidden if needed).

### 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:
  - [ ] Gallery snaps per slide with wheel, keys and buttons
  - [ ] Caption updates to the active slide's client
  - [ ] JavaScript payload stays under 250KB gzipped
  - [ ] Mobile layout falls back to vertical list
  - [ ] Invalid site.json shows an error panel

Open the builderAll templatesThis palette on its own