Skip to main content
vibld

Template

Theo Achterberg

a site for a literary novelist with three books out and a fourth coming that sells the new book first, keeps every book findable, lists readings and grows the newsletter.

Author site for a novelist · Website · Portfolio · 5 pages

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

Caslon is the face of English books; Literata was drawn for long reading on screens, so excerpts read like the book.

  • Libre Caslon DisplayHeadings: titles, pull quotes and the author’s name
  • LiterataBody: body, excerpts and event details

Who it is for

  • Readers who just finished a book and want more
  • Booksellers and event organizers
  • Press and the author’s publisher

Layout

  1. Masthead: the author’s name centered in Caslon, Books, Events, About, Contact
  2. Split hero: the new book’s cover as a 3D object left; title, one-line pitch, release date and retailer buttons right
  3. Praise: three short quotes with their sources
  4. Other books grid: covers with year and one line each
  5. Upcoming events list: date, city, venue
  6. Newsletter sign-up form with how often it comes
  7. Footer with agent contact and social links

Palette

Literary and tactile, like the endpapers of a good hardcover: cream stock, oxblood cloth, ink that looks letterpressed.

  • cream stock#f6f0e4
  • letterpress ink#22201c
  • oxblood#6b1f2a
  • linen#e9dfcc

Every checked pair, measured again

SampleWhereRatioNeeds
Aabody text on the page14.33:14.5:1
Aatext on cards12.31:14.5:1
Aasecondary text on muted surfaces5.69:14.5:1
Aasecondary text on the page6.65:14.5:1
Aalabel on the primary action9.98:14.5:1
Aalabel on secondary surfaces12.31:14.5:1
Aalabel on the accent12.31:14.5:1
Aaerror label5.46:14.5:1
primary action against the page9.98: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
Libre Caslon Display, titles, pull quotes and the author’s name
Body
Literata, body, excerpts and event details

Spacing and imagery

Book-like: generous margins, a 62ch measure, 112px between sections.

Book covers as objects with real depth and shadow, an author portrait in natural light, and textures of paper and cloth.

Components

  • 3D book: the cover with a spine and page edge in CSS 3D, tilting toward the pointer
  • Retailer button row with the independent bookshop first
  • Excerpt reader with a drop cap and a "keep reading" fold

Interactions

  • Book pages open with the excerpt folded; "Keep reading" opens it in place
  • Events in the past move to a past-events list on their own by date

Data

  • books: a book: title, year, cover, pitch, synopsis, excerpt in Markdown, praise, retailer links (bookshop, independent store, major retailers, audiobook), reading guide PDF
  • events: an event: date, time, city, venue, with whom, ticket or RSVP link
  • form newsletter: email, first name
  • form contact: name, email, kind (reader, book club, event, press), 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
Each niche site prompt describes a whole small site for one kind of owner: its pages, the records it keeps, the forms it collects and the tools it links to. The rules below apply to every one of them.

### Niche site principles
- The site does the one job its owner needs most (a sign-up, an RSVP, a request, a visit) on the first screen, and every page leads back to it.
- Records the owner adds often (sermons, events, listings, galleries, menus, tour dates) are content collections in `src/content/`, each record with a slug, so a new record gets its page with no code change.
- Tools the owner already pays for or uses (giving, tickets, booking, listing search, ordering) are linked, or framed in an `<iframe>` whose address is in `content.ts`, never rebuilt. With no address, a plain button links out instead, and nothing pretends to work.
- Copy is written for the owner's visitors, specific and plain. Dates, times and places are real fields, never baked into prose.
- The design is this site's own. Its layout, type and motion follow the brief, not a shared template.

### Forms
Every form is a plain HTML form, `<form method="post" action="/__vibld/forms/<name>">`, named as the brief names it (lowercase letters, digits and hyphens). Fields are ordinary named inputs; checkboxes repeat their name; no file uploads. Add a hidden `_next` input with the path to land on, and show a thank-you there when the address has `?submitted=<name>`. Add an empty hidden `_gotcha` input. A script may post it instead with `fetch(form.action, { method: 'POST', body: new FormData(form), headers: { accept: 'application/json' } })`, which answers `{ ok: true }` or `{ ok: false, error }`. A form with limited places lists them in `public/vibld.forms.json` (`{"forms":{"<name>":{"slots":{"field":"<field>","options":{"<value>":<places>}}}}}`), the field a select or radio whose values match those keys exactly; `GET /__vibld/forms/<name>/slots` returns `{ field, options: [{ value, capacity, taken, left }] }`, which the page reads to show what is left and disable full options. vibld adds bot protection when the page is served.

### Engineering baseline
- TypeScript strict mode, small typed components, and one source of truth for design tokens (CSS variables consumed by Tailwind).
- All copy lives in typed content files, so the owner can edit words without touching layout.
- Every form validates on the client, says what went wrong in plain words beside the field, and never claims success it has not had.
- No secrets in the bundle and no third-party scripts beyond Google Fonts; an owner's tool comes in only as a link or a framed page.
### Goal
Build **Theo Achterberg**: a site for a literary novelist with three books out and a fourth coming that sells the new book first, keeps every book findable, lists readings and grows the newsletter.

### Stack
React + TypeScript + Vite, Tailwind CSS and React Router, one route per page. Content collections in `src/content/`, forms posting to vibld (see Forms in the baseline). No backend of its own.

### Pages & layout
- `/` Home: new book hero with pre-order links, praise, other books, upcoming events, newsletter
- `/books` Books: every book, each with its page
- `/events` Events: upcoming readings and past events
- `/about` About: bio in two lengths, portrait, press kit download
- `/contact` Contact: agent, publicist and a reader contact form

Home, top to bottom:
1. Masthead: the author’s name centered in Caslon, Books, Events, About, Contact.
2. Split hero: the new book’s cover as a 3D object left; title, one-line pitch, release date and retailer buttons right.
3. Praise: three short quotes with their sources.
4. Other books grid: covers with year and one line each.
5. Upcoming events list: date, city, venue.
6. Newsletter sign-up form with how often it comes.
7. Footer with agent contact and social links.

Copy to start from, in `content.ts`: headline "The Salt Year", subcopy "A novel about a family, a failing lighthouse and the winter that changed both. Out March 3.", primary action "Pre-order".

### Design system
Mood: Literary and tactile, like the endpapers of a good hardcover: cream stock, oxblood cloth, ink that looks letterpressed.

Palette: cream stock `#f6f0e4`, letterpress ink `#22201c`, oxblood `#6b1f2a`, linen `#e9dfcc`. Tokens: background `#f6f0e4`, foreground `#22201c`, primary `#6b1f2a` with `#f6f0e4` labels, cards `#e9dfcc`, accent `#e9dfcc`.

Type: Libre Caslon Display for titles, pull quotes and the author’s name; Literata for body, excerpts and event details. Load both from https://fonts.googleapis.com/css2?family=Libre+Caslon+Display&family=Literata:wght@400;600&display=swap.

Corners: 2px on controls, 4px on cards, 6px on large panels. Spacing: Book-like: generous margins, a 62ch measure, 112px between sections.

Imagery: Book covers as objects with real depth and shadow, an author portrait in natural light, and textures of paper and cloth. Use the owner's photos where the project has them. Without them, use the project's stock photos, or shapes and color from the palette; never a stock photo of people at desks.

### Components & interactions
- 3D book: the cover with a spine and page edge in CSS 3D, tilting toward the pointer
- Retailer button row with the independent bookshop first
- Excerpt reader with a drop cap and a "keep reading" fold

Motion:
- Book pages open with the excerpt folded; "Keep reading" opens it in place
- Events in the past move to a past-events list on their own by date

The signature motion is: the new book tilts toward the pointer and a soft highlight slides across its cover, as light catches a jacket in a shop window. Keep it to that one; everything else is a 150 to 300ms state change. With prefers-reduced-motion, it and every reveal are still.

### Data & state
Collections:
- `src/content/books.json`: a book: title, year, cover, pitch, synopsis, excerpt in Markdown, praise, retailer links (bookshop, independent store, major retailers, audiobook), reading guide PDF; each has its page at `/books/<slug>`
- `src/content/events.json`: an event: date, time, city, venue, with whom, ticket or RSVP link

Forms:
- `newsletter`: A reader joins the newsletter. Fields: email, first name.
- `contact`: Readers, book clubs and organizers write in. Fields: name, email, kind (reader, book club, event, press), message.

Linked tools:
- Retailer links for each book, starting with an independent bookshop link.
- Event tickets or RSVPs on the venue’s own page.

### Accessibility
WCAG 2.2 AA. Every control has a visible focus ring and a 44px target, every form field a visible label, and errors are announced. Dates and times are written out ("Sunday, March 8, 10:30 AM"), not only shown in a grid. Images have alt text that says what is in them. Verified contrast: body text on the page #22201c on #f6f0e4 14.32:1; text on cards #22201c on #e9dfcc 12.30:1; secondary text on muted surfaces #57544e on #e5dfd4 5.68:1; secondary text on the page #57544e on #f6f0e4 6.64:1; label on the primary action #f6f0e4 on #6b1f2a 9.97:1; label on secondary surfaces #22201c on #e9dfcc 12.30:1; label on the accent #22201c on #e9dfcc 12.30:1; error label #ffffff on #c62f2f 5.45:1; primary action against the page #6b1f2a on #f6f0e4 9.97:1.

### Security
No third-party scripts other than Google Fonts. Framed tools are `<iframe>`s from the owner's own address with a `title`, `loading="lazy"` and `referrerpolicy="strict-origin-when-cross-origin"`. Forms cap input length and carry the empty `_gotcha` field.

### Performance & SEO
Images as AVIF or WebP with width and height, the first one eager and the rest lazy. Preconnect to Google Fonts. Each page has its own title and description from content, and records' pages take theirs from the record. Structured data where it fits: Person and CreativeWork.

### Guardrails
- Avoid: A quill or typewriter motif, cursive headings, a full-screen popup for the newsletter, and stock photos of coffee and open books.
- One primary action per screen, one accent color, at most six top-level links.
- No carousel in the hero, no mega menu, no emoji or clip-art icons, no hard offset shadows, no purple-to-blue gradient.
- The names in it are invented. Use no real organization's or person's name, logo or trademark.

Open the builderAll templatesThis palette on its own