Template
Westfield High, Class of 2017
a site for a ten-year high school reunion that sells tickets through the organizers’ ticket page, finds classmates, shares "where are they now" updates, and remembers classmates who have passed.
Ten-year class reunion with tickets and classmate updates · Website · Events and bookings · 4 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.
Start from this templateRead the build prompt
Typefaces
Graduate is cut like collegiate block lettering on a jacket; Saira’s squared shapes fit yearbook grids and echo the jacket lettering.
- GraduateHeadings: the class year, headlines and section titles
- SairaBody: body, updates and forms
Who it is for
- Classmates deciding whether to go
- Classmates who lost touch and want to be found
- The reunion committee
Layout
- Nav: the class year in Graduate, Updates, Find a classmate, In memory, and Get tickets
- Hero: "2017" huge in gold block letters over a navy field, the headline and the date
- The night: three cards (dinner, music, the photo booth) with times
- Tickets pricing: early, regular and plus-one, linking to the ticket page
- Where are they now grid of yearbook-style cards with then and now photos
- Find a classmate list of names with a "know where they are" form
- In memory list, then footer with committee email
Palette
Varsity and nostalgic, like a letter jacket in navy and gold: athletic block type, yearbook grids, a little cheek.
- varsity navy
#0e1b33 - chalk
#f4f1e8 - gold
#f2b630 - jersey blue
#1d3157
Every checked pair, measured again
| Sample | Where | Ratio | Needs |
|---|---|---|---|
| Aa | body text on the page | 15.20:1 | 4.5:1 |
| Aa | text on cards | 11.41:1 | 4.5:1 |
| Aa | secondary text on muted surfaces | 7.36:1 | 4.5:1 |
| Aa | secondary text on the page | 9.01:1 | 4.5:1 |
| Aa | label on the primary action | 9.41:1 | 4.5:1 |
| Aa | label on secondary surfaces | 11.41:1 | 4.5:1 |
| Aa | label on the accent | 11.41:1 | 4.5:1 |
| Aa | error label | 5.46:1 | 4.5:1 |
| primary action against the page | 9.41:1 | 3: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
- Graduate, the class year, headlines and section titles
- Body
- Saira, body, updates and forms
Spacing and imagery
Yearbook-tight grids, 72px between sections.
Yearbook photos and candids from 2017 next to new ones; the school’s mascot drawn simply, never a real school’s logo.
Components
- Yearbook card: then and now photos side by side with name and city
- Ticket tier card with what is included and a Buy button
- Jersey-number style counter of classmates coming, entered by the committee
Interactions
- Search box filters the find-a-classmate list as you type
- Updates are shown only once the committee adds them to the collection
Data
updates: an update a classmate sent and agreed to share: name, then photo, now photo, city, a few linesmissing: a classmate the committee cannot reach: name as in the yearbookmemory: a classmate who has passed: name, a few words, photoform update: name in 2017, name now, email, city, what you have been up to, may we post it (yes or no)form classmate-tip: your name, classmate’s name, how to reach them or who might know
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 **Westfield High, Class of 2017**: a site for a ten-year high school reunion that sells tickets through the organizers’ ticket page, finds classmates, shares "where are they now" updates, and remembers classmates who have passed.
### 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
- `/` Reunion: hero, the night, tickets, where are they now, find a classmate, in memory
- `/updates` Where are they now: classmates’ updates
- `/find` Find a classmate: the list of classmates we cannot reach, and a tip form
- `/in-memory` In memory: classmates who have passed
Home, top to bottom:
1. Nav: the class year in Graduate, Updates, Find a classmate, In memory, and Get tickets.
2. Hero: "2017" huge in gold block letters over a navy field, the headline and the date.
3. The night: three cards (dinner, music, the photo booth) with times.
4. Tickets pricing: early, regular and plus-one, linking to the ticket page.
5. Where are they now grid of yearbook-style cards with then and now photos.
6. Find a classmate list of names with a "know where they are" form.
7. In memory list, then footer with committee email.
Copy to start from, in `content.ts`: headline "Ten years. One night. Class of 2017.", subcopy "Saturday, October 9, 2027 at the Riverside Ballroom. Dinner, a DJ who will play the songs, and everyone you meant to text.", primary action "Get tickets".
### Design system
Mood: Varsity and nostalgic, like a letter jacket in navy and gold: athletic block type, yearbook grids, a little cheek.
Palette: varsity navy `#0e1b33`, chalk `#f4f1e8`, gold `#f2b630`, jersey blue `#1d3157`. Tokens: background `#0e1b33`, foreground `#f4f1e8`, primary `#f2b630` with `#0e1b33` labels, cards `#1d3157`, accent `#1d3157`.
Type: Graduate for the class year, headlines and section titles; Saira for body, updates and forms. Load both from https://fonts.googleapis.com/css2?family=Graduate&family=Saira:wght@400;600&display=swap.
Corners: 4px on controls, 10px on cards, 16px on large panels. Spacing: Yearbook-tight grids, 72px between sections.
Imagery: Yearbook photos and candids from 2017 next to new ones; the school’s mascot drawn simply, never a real school’s logo. 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
- Yearbook card: then and now photos side by side with name and city
- Ticket tier card with what is included and a Buy button
- Jersey-number style counter of classmates coming, entered by the committee
Motion:
- Search box filters the find-a-classmate list as you type
- Updates are shown only once the committee adds them to the collection
The signature motion is: the gold "2017" stamps into the hero with a short, heavy scale-down like a letter pressed into felt. 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/updates.json`: an update a classmate sent and agreed to share: name, then photo, now photo, city, a few lines
- `src/content/missing.json`: a classmate the committee cannot reach: name as in the yearbook
- `src/content/memory.json`: a classmate who has passed: name, a few words, photo
Forms:
- `update`: A classmate shares an update for the site. Fields: name in 2017, name now, email, city, what you have been up to, may we post it (yes or no).
- `classmate-tip`: Someone helps find a classmate. Fields: your name, classmate’s name, how to reach them or who might know.
Linked tools:
- Tickets: the committee’s ticketing page (Eventbrite, Ticket Tailor or a payment app).
### 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 #f4f1e8 on #0e1b33 15.20:1; text on cards #f4f1e8 on #1d3157 11.41:1; secondary text on muted surfaces #bbbcbb on #202c41 7.35:1; secondary text on the page #bbbcbb on #0e1b33 9.01:1; label on the primary action #0e1b33 on #f2b630 9.40:1; label on secondary surfaces #f4f1e8 on #1d3157 11.41:1; label on the accent #f4f1e8 on #1d3157 11.41:1; error label #ffffff on #c62f2f 5.45:1; primary action against the page #f2b630 on #0e1b33 9.40: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: Event.
### Guardrails
- Avoid: Any real school’s name, crest or mascot, posting classmates’ contact details, a public list of who bought tickets, and sports-photo stock.
- 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.