Template
Aspenfold
A marketing-site theme for a small business or startup that includes several landing-page variants, a full blog with tags, a contact form and a component kit. Its signature is a theme switcher that re-skins buttons, shapes, surfaces and fonts from a few CSS variables, so teams can match their brand quickly.
Themeable business marketing site with blog and landing-page variants · Website · SaaS landing page · 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
Baskervville is a bookish transitional serif that gives the boutique-agency headings their editorial calm, the named Lato body is kept, and the two theme presets get their own sans and mono.
- BaskervvilleHeadings: headings 44px / 32px / 22px 700, -0.01em
- LatoBody: body 16px/1.6 400, captions 14px
- Atkinson HyperlegibleAccent: all-sans theme preset
- Anonymous ProFigures and code: mono-accent theme preset
Patterns
- split hero: serif headline left, large rounded monochrome photo right
- black pill primary button + text secondary
- icon mini-feature row under hero CTAs
- landing-page variant gallery in grey rounded tiles
- blog index with hero newsletter panel and two-column post cards
- tag filtering on blog
- live theme switcher driven by CSS variables
- four-column footer with social icons and CTA
States it is designed for
- Contact form: field errors, submitting, success, provider error with retry
- Subscribe: invalid email, already subscribed, success
- Blog tag filter with no matching posts: empty state with 'Clear filter'
- Image loading: fixed-ratio grey placeholder
- Theme preset not found in storage: fall back to default
- Long post titles clamp to 2 lines on cards
Who it is for
- small businesses and startups needing a site fast
- freelance web designers reusing a base theme
- content marketers who want a built-in blog
Layout
- Header: wordmark left; text links (Home, Blog, About, Contact) and a black pill 'Get started' right; collapses to a menu button on mobile
- Hero: two columns; left has 44px serif headline, short sans paragraph, black pill CTA + text link, and a row of five tiny icon features with captions; right has a tall rounded (24px) monochrome landscape photo
- Landing pages section: serif heading + one-line intro; grid of grey rounded tiles each showing a preview thumbnail and a centred title; a 'Coming soon' tile with blurred preview
- Blog index: grey rounded hero panel with serif title, one-line intro and inline email subscribe; 'Recent posts' two-column cards (image, serif title, two-line excerpt, date, tags)
- Blog post: 720px prose column, serif headings, author and date line, tag chips, related posts
- Contact: two columns (copy + details left, form right)
- Footer: wordmark, social icon row and a small pill CTA left; three link columns (Landing pages, Company, Theme)
- Floating theme switcher button bottom-right opening a panel of preset themes
- Mobile: hero stacks with photo below text; post grid becomes single column
Palette
Editorial, calm and monochrome. Photography and serif type give it a boutique-agency feel.
- page background
#ffffff - soft panel / tile
#f0f0ef - primary text & pill button
#111111 - secondary text
#5f5d5b - hairline / tile border (decorative)
#d6d5d3 - dark footer variant
#1f1d1b - link accent
#1d4ed8 - input border
#7a7876
Every checked pair, measured again
| Sample | Where | Ratio | Needs |
|---|---|---|---|
| Aa | body text on white | 18.88:1 | 4.5:1 |
| Aa | secondary text on panel | 5.75:1 | 4.5:1 |
| Aa | pill button label | 18.88:1 | 4.5:1 |
| Aa | link accent on white | 6.70:1 | 4.5:1 |
| input border on white | 4.40:1 | 3:1 | |
| Aa | text on dark footer | 16.80:1 | 4.5:1 |
| Aa | muted text on dark footer | 11.46:1 | 4.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
- Baskervville 700 (a bookish transitional serif similar to the observed one), 44px hero, 32px section heads, 22px card titles, -0.01em tracking
- Body
- Lato 400 16px/1.6 (close to the observed humanist sans); captions 14px
Serif for every heading, sans for everything else. Theme presets may swap the pair (e.g. an all-sans or a mono preset).
Spacing and imagery
Comfortable: container 1120px; section padding 96px; tile gap 16px; card padding 16px. Radius 24px photos and panels, 12px tiles, pills fully rounded. Shadows: none by default (themes can add). 8px grid.
Large black-and-white landscape photography with soft rounded corners; blog uses warm lifestyle photos cropped 3:2; small line icons for the mini feature row.
Components
- SiteHeader
- SplitHero
- PillButton
- MiniFeatureRow
- LandingVariantTile
- NewsletterPanel
- PostCard
- TagChip
- ProsePost
- ContactForm
- SiteFooter
- ThemeSwitcher panel
Interactions
- Theme switcher applies a preset by swapping a data-theme attribute; choice persists in localStorage
- Tiles and post cards darken their background slightly and underline the title on hover
- Tag chips filter the blog index client-side and update the URL
- Contact and subscribe forms validate inline and show success in place
- Mobile menu slides down with focus trap and Escape to close
Data
Post{slug, title, excerpt, cover, coverAlt, date, author, tags[], body (markdown)}Tag{slug, label}LandingVariant{slug, title, thumbnail, status (live|coming-soon)}ThemePreset{id, label, tokens{bg, surface, text, accent, radius, fontDisplay, fontBody}}ContactMessage{name, email, message}
Guardrails
Experience
- Keep one black pill CTA per section; secondary actions are text links
- Landing variants must each be real pages, not dead tiles; 'Coming soon' tiles are non-interactive
- Blog cards always show date and at least one tag
- Theme switcher must never change content or layout, only tokens
- Hero photo must support the message, not just decorate; crop consistently
Accessibility
- Every theme preset must pass AA; validate each preset's text/background pairs in CI
- Photos have meaningful alt text; decorative landscapes use empty alt
- Theme switcher is a labelled radio group inside a dialog
- Serif headings at 22px+ only; body stays sans 16px
- Input borders #7a7876 (4.4:1) keep fields visible on white
Security
- Contact form posts through a serverless function with zod validation and a honeypot
- Rate-limit contact submissions and strip HTML from messages
- Use a form or email provider via server-side secret, never in client code
- Collect only name, email and message; state the retention period on the page
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 an entry'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 entries) - 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. ### SaaS screen baseline - Design every screen for its full set of states: first-run empty, loading skeleton, partial data, error with retry, permission-denied, and success feedback. Each entry lists the states its screen needs. - Keep destructive actions (delete, revoke, downgrade, remove member) behind a confirmation that names the object, and prefer undo over a second dialog where the action is reversible. - Enforce authorisation on the server for every action a screen exposes. Hiding a button is not access control; check the role again in the API or RLS policy. - Never show secrets (API keys, tokens) in full after creation. Show them once, then mask them, and offer rotate and revoke. - Keep the app shell (navigation, workspace switcher, account menu) consistent across screens, and preserve filters, sort and scroll position when the user navigates back.
### Goal
Build **Aspenfold**, a themeable marketing site for a small business or startup. It includes a homepage with a split hero, several landing-page variants, a blog with tags, an about page, a contact form and a small component kit. A floating theme switcher shows how the whole look changes by swapping a few CSS variables.
### Stack
Astro + TypeScript, Tailwind CSS mapped to CSS variables, content collections for posts, lucide icons, zod for form validation. The contact form posts to a serverless endpoint that forwards to a transactional email service. No client framework except small islands (menu, theme switcher, tag filter).
### Pages & layout
1. **Home**: header (wordmark; Home, Blog, About, Contact; black pill "Get started"). Split hero: serif headline ("Grow a business people remember"), two-line sans intro, pill CTA + "Read the guide" text link, a row of five small icon features with one-word captions; right column a tall 24px-radius black-and-white landscape photo. Then "Landing pages": grid of grey rounded tiles with thumbnail and title, plus a blurred "Coming soon" tile. Then a latest-posts strip and footer.
2. **Landing variants (`/landing/1`, `/landing/2`)**: alternative hero and section orders built from the same components.
3. **Blog index**: grey rounded panel with serif title, intro and inline subscribe; tag chips; two-column post cards (3:2 image, serif title, excerpt, date, tags).
4. **Post**: 720px prose, serif headings, author/date line, tag chips, related posts.
5. **About** and **Contact** (copy left, form right).
6. **Footer**: wordmark, social icons, small pill CTA; columns Landing pages, Company, Theme.
7. **Responsive**: hero stacks (text then photo); grids collapse to one column under 720px; the menu becomes a slide-down panel.
### Design system
- Colors (default theme): `--bg: #ffffff`, `--panel: #f0f0ef`, `--text: #111111`, `--text-2: #5f5d5b`, `--hairline: #d6d5d3` (decorative), `--footer-dark: #1f1d1b`, `--link: #1d4ed8`, `--input-border: #7a7876`. Buttons use `--text` as fill with white labels.
- Fonts: Baskervville 700 for headings (44/32/22px, -0.01em); Lato 400 for body at 16px/1.6; captions 14px. Presets may swap to an all-sans pairing (Atkinson Hyperlegible) or a mono accent (Anonymous Pro).
- Spacing: 8px grid; section padding 96px; container 1120px; tile gap 16px.
- Radius: `--radius-lg: 24px` (photos, panels), `--radius-md: 12px` (tiles, cards), pills 999px.
- Shadows: `--shadow: none` by default; presets may set a soft shadow.
- Motion: 150ms hover transitions; theme changes crossfade 200ms; disabled under reduced motion.
- Theme presets: Default (monochrome), Warm (cream background, terracotta accent), Night (dark background, light text). Each preset is only a token map.
### Components & interactions
SiteHeader, SplitHero, PillButton, MiniFeatureRow, LandingVariantTile, NewsletterPanel, PostCard, TagChip, ProsePost, ContactForm, SiteFooter, ThemeSwitcher. The switcher is a floating button that opens a dialog with preset radio cards; selecting one sets `data-theme` on `<html>` and stores it in localStorage (wrapped in try/catch). Tag chips filter posts client-side and write `?tag=`. Cards darken their panel on hover and underline titles.
### Data & state
Posts: `{slug, title, excerpt, cover, coverAlt, date, author, tags, body}` from markdown. `LandingVariant {slug, title, thumbnail, status}`. `ThemePreset {id, label, tokens}`. Contact: `{name, email, message}` validated by zod. Seed six invented posts (for example about pricing experiments and hiring a first designer) with royalty-free or generated imagery.
### Accessibility
Landmarks and one h1 per page. The theme dialog has a heading, radio group and Escape to close; focus returns to the trigger. Tag filters are toggle buttons with `aria-pressed`. Photos carry alt text; purely decorative ones use `alt=""`. Body text stays sans 16px; serif only at 22px+. Every preset's pairs are checked in CI.
Verified contrast: body text on white: #111111 on #ffffff = 18.88:1; secondary text on panel: #5f5d5b on #f0f0ef = 5.75:1; pill button label: #ffffff on #111111 = 18.88:1; link accent on white: #1d4ed8 on #ffffff = 6.7:1; input border on white: #7a7876 on #ffffff = 4.4:1; text on dark footer: #ffffff on #1f1d1b = 16.8:1; muted text on dark footer: #d6d5d3 on #1f1d1b = 11.46:1.
### Security
The contact endpoint validates with zod, enforces length limits, strips HTML, uses a honeypot and rate-limits by IP. Email provider keys live in server environment variables only. Subscribe uses double opt-in. No third-party trackers by default; collect only what the forms need.
### Performance & SEO
Static output with zero JS on posts. Responsive images (AVIF/WebP, width/height set), lazy below the fold. Self-host subsetted Baskervville and Lato. Per-page title, description, canonical, OG image, sitemap and RSS. Target a perfect Lighthouse score on home and posts.
### Guardrails
- Write original headlines and post content; no copied theme text.
- Use generic photography you have rights to or generated imagery.
- Theme presets change tokens only, never markup.
- Acceptance criteria:
- [ ] All presets pass the recorded contrast pairs
- [ ] Tag filter, subscribe and contact form work with keyboard only
- [ ] Landing variants render from shared components
- [ ] Theme choice persists across pages and falls back safely
- [ ] Lighthouse 100 performance on home