Skip to main content
vibld

Template

Cantilever House

A dark, cinematic portfolio for an architecture and interiors studio where typography carries the imagery: the hero headline is masked over playing video, and project cards fill their names with each project's photograph. Project pages, team bios and a contact form complete the site.

Architecture and interiors 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.

Start from this templateRead the build prompt

Typefaces

Noto Sans Display has a heavy, tightly fitting bold that works when imagery sits inside the letterforms, and it stays neutral in text.

  • Noto Sans DisplayHeadings: hero ~96px bold, card titles ~56px, tight leading
  • Noto Sans DisplayBody: body 16px

Who it is for

  • Architecture and interior design studios
  • Studios bidding for commercial work
  • Firms showcasing residential renovations
  • Practices expanding into new cities

Layout

  1. Scroll-reactive header: bold wordmark left, Work / About / Our Team / Contact right with underline on active
  2. Full-bleed architectural video/photo hero with two-line bold headline; second line filled with the video through text masking
  3. Black 2-column project grid separated by hairline rules: each cell has a two-line project descriptor in white and project name filled with its photo (image-masked text)
  4. Project detail pages: full-bleed hero, year/location/scope metadata, description
  5. Team bios page
  6. Contact page with form
  7. Footer with nav and copyright

Palette

Cinematic, bold, sophisticated, dark, architectural. It turns project names into windows onto the buildings.

  • page background (light pages)#ffffff
  • work grid background#000000
  • text on dark#ffffff
  • foreground#09090b
  • muted text (light pages)#52525b
  • primary#18181b
  • decorative grid rule#3f3f46
  • muted surface#f4f4f5
  • input border#8c8c99
  • dark mode muted text#a1a1aa
  • hero overlay (black 60%)#00000099

Every checked pair, measured again

SampleWhereRatioNeeds
Aalight: body text19.90:14.5:1
Aalight: muted text on white7.73:14.5:1
Aalight: muted text on muted surface7.03:14.5:1
Aalight: white on primary button17.72:14.5:1
light: input border3.32:13:1
Aawork grid descriptor text on black21.00:14.5:1
masked project name stroke (56px+) on black21.00:13:1
focus ring on black grid21.00:13:1
Aahero solid line over 60% black overlay on white-worst-case footage5.74:14.5:1
Aadark: body text19.06:14.5:1
Aadark: muted text on card6.91:14.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
Bold system sans (~96px hero, ~56px card titles), tight leading, sentence case with period endings (the system face is not on Google Fonts; a vibld project loads Noto Sans Display)
Body
System sans 16px (the system face is not on Google Fonts; a vibld project loads Noto Sans Display)

One heavy sans; the imagery lives inside letterforms rather than beside them

Spacing and imagery

Full-bleed hero; project grid of two equal columns with 1px rules, ~360px tall cells, 52px inner padding; square corners

Architectural photography and video (curved concrete, glazing, stairs) shown through text masks and full-bleed on project pages; slow drift animation

Components

  • Scroll-reactive header
  • Video-masked hero headline
  • Canvas video renderer
  • Image-masked project title cards
  • Hairline project grid
  • Project detail hero
  • Metadata row (year, location, scope)
  • Team member cards
  • Contact form with toast
  • Theme provider
  • Footer nav

Interactions

  • Video plays behind masked hero text
  • Masked card images slowly drift
  • Header background changes on scroll
  • Card hover brightens and reveals arrow
  • Route transitions
  • Form submission toast
  • Light/dark theme support

Data

  • Project{slug, descriptor, name, year, location, scope, heroImage, images[], description}
  • TeamMember{name, role, bio, photo}
  • ContactMessage{name, email, company, 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 portfolio site for a fictional architecture and interiors studio called **Cantilever House**. The audience is developers, hospitality groups and homeowners looking for a high-end studio. The signature idea: imagery lives inside the typography. The hero headline is filled with moving footage and each project's name is filled with its own photograph, set in a black grid. Project pages, team bios and a contact form complete the site.

### Stack
React 18 + TypeScript + Vite, Tailwind CSS, shadcn/ui (Radix), lucide-react, TanStack Router (or React Router) for typed routes, Framer Motion for drift and route transitions, Sonner for toasts, next-themes for theme handling, and react-hook-form + zod for the contact form. Text masking uses `background-clip: text` for images and a `<canvas>` or `mix-blend-mode` approach for video. The contact form posts to one serverless function.

### Pages & layout
1. Header: bold wordmark left and four links right with an underline on the active link; transparent over the hero, solid black with a bottom rule after scroll.
2. Hero (90vh): full-bleed architectural photo or video under a 60% black overlay, with the headline on two lines: the first solid white, the second filled with the moving footage.
3. Work grid: black background, two equal columns separated by 1px rules; each cell holds a two-line descriptor in white bold ("Double height") and the project name below, filled with that project's photo and ending in a period.
4. Project page: full-bleed hero, a metadata row (year, location, scope, area), narrative text and a gallery, with next and previous links.
5. About and Team: studio text; team cards with portrait, name, role and short bio.
6. Contact: form plus studio address and email; footer repeats the navigation.

### Design system
Tokens: `--background: #ffffff; --foreground: #09090b; --primary: #18181b; --muted: #f4f4f5; --border: #e4e4e7 (decorative); --input-border: #8c8c99; --muted-foreground: #52525b; --work-bg: #000000; --work-rule: #3f3f46 (decorative)`. Dark mode for content pages: `--background: #09090b; --foreground: #fafafa; --muted-foreground: #a1a1aa; --card: #18181b`. Font: Noto Sans Display 700/800 for display and Noto Sans Display 400 for body. Scale: clamp(56px, 8vw, 104px) hero; 56px card names; 20 / 16 / 14px (16px body at line-height 1.6, max 70ch). Spacing: 52px cell padding, 360px minimum cell height, 8px base. Square corners. Motion: masked images drift `background-position` over 20s linear alternate; header transition 200ms; route fade 300ms. Dark work grid, light content pages; dark mode flips content pages.

### Components & interactions
- MaskedText: props for image or video source; falls back to solid text when `background-clip: text` is unsupported or the image fails.
- Video mask: pauses when off-screen (IntersectionObserver) and when the tab is hidden.
- Project cell: hover increases image brightness and shows an arrow; focus ring; the whole cell is one link.
- Contact form: labelled fields, inline errors, submit spinner, success and error toasts.
- Empty state for team if no members; 404 for unknown project slugs.

### Data & state
`Project{slug,descriptor,name,year,location,scope,area?,hero,images[],body}`, `TeamMember{name,role,bio,photo}`. Static typed data. Seed nine projects with invented names and cities.

### Accessibility
Image-filled text can have poor contrast, so every masked name (56px and up) gets a 1.5px #ffffff text stroke that guarantees the letter edges reach 3:1 against black whatever the photo, and each link takes its accessible name from plain data. The solid first hero line sits over a 60% black overlay (5.7:1 on a white-worst-case frame). Light pages use #52525b for muted text and #8c8c99 input borders. The masked hero line must exist as real text for screen readers. Provide a pause control for the hero video and stop it under `prefers-reduced-motion`, which also disables drift. Keep a visible focus ring on black. Verified contrast: light: muted text on white: #52525b on #ffffff = 7.73:1; masked project name stroke: #ffffff on #000000 = 21.0:1; hero solid line over 60% black overlay on white-worst-case footage: #ffffff on #666666 = 5.74:1.

### Security
Validate the contact form with zod on the client and in the function; add a honeypot and rate limit. Keep API keys server-side. External links use `rel="noopener noreferrer"`.

### Performance & SEO
Keep the hero video short and compressed with a poster; lazy-load project images used as masks (use small, 800px-wide crops). Code-split project pages. Per-project titles, descriptions and OG images; Organization JSON-LD. Watch CLS by giving cells fixed heights.

### Guardrails
- Use original copy and placeholder or generated architecture imagery; don't claim real buildings.
- No fabricated client quotes.
- Store only contact form fields.
- Keep components small and typed, never use `any`, and handle media failures visibly.
- Done when: masked text falls back gracefully without image support; the hero video pauses off-screen and under reduced motion; each project cell has a clear accessible name; project pages resolve by slug; the contact form shows success and error states.

Open the builderAll templatesThis palette on its own