Skip to main content
vibld

Template

Northpoint Heating & Air

a site for a family-owned heating and cooling contractor that gets an emergency caller on the phone in one tap, shows the service area, and turns everyone else into a quote request with the details a technician needs.

HVAC contractor site · Website · Small business site · 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

Saira Condensed fits a phone number large on a narrow screen, like van lettering; Encode Sans is plain and sturdy.

  • Saira CondensedHeadings: headlines, the phone number and service names
  • Encode SansBody: body, the quote form and service area

Who it is for

  • Homeowners with no heat or no cooling, right now
  • Homeowners planning a replacement
  • Property managers with several units

Layout

  1. Emergency banner across the top: 24/7 emergency service with the phone number
  2. Header: logo, Services, Service area, About, the phone number in red, and Request a quote
  3. Split hero: headline and Call now left, a technician photo right with "Same-day service" chip
  4. Services grid: furnace repair, AC repair, heat pumps, tune-ups, new systems, indoor air
  5. Service area: a list of towns with a ZIP code check
  6. Quote request form preview with the first step
  7. Reviews: three short reviews with first names and towns
  8. Licenses and insurance strip with license numbers, then footer with hours and phone

Palette

Dependable and direct, like a service van with clean lettering: white, a deep navy, a heat red and a cool blue.

  • white#ffffff
  • van navy#0d1b2a
  • heat red#c8300f
  • cool blue#dbe9fb

Every checked pair, measured again

SampleWhereRatioNeeds
Aabody text on the page17.39:14.5:1
Aatext on cards15.91:14.5:1
Aasecondary text on muted surfaces6.58:14.5:1
Aasecondary text on the page7.71:14.5:1
Aalabel on the primary action5.40:14.5:1
Aalabel on secondary surfaces15.91:14.5:1
Aalabel on the accent14.13:14.5:1
Aaerror label5.46:14.5:1
primary action against the page5.40: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
Saira Condensed, headlines, the phone number and service names
Body
Encode Sans, body, the quote form and service area

Spacing and imagery

Efficient: 64 to 80px between sections, big tap targets.

The company’s own technicians and vans, real equipment installs, the service area map; no cartoon thermometers.

Components

  • Sticky call bar on phones with Call now and Request a quote
  • ZIP check: input that says whether the ZIP is in the service area from towns.json
  • Multi-step quote form (contact, system, timing) that posts once at the end

Interactions

  • ZIP check answers as you type the fifth digit
  • The quote form remembers its steps if the visitor goes back

Data

  • services: a service: name, summary, signs you need it, what we do, typical time
  • towns: a town served: name, ZIP codes
  • reviews: a review: first name, town, text, date, where it was posted
  • form quote: name, phone, email, ZIP code, service (select), system type (furnace, AC, heat pump, boiler, not sure), age of system, what is happening, preferred visit time

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 **Northpoint Heating & Air**: a site for a family-owned heating and cooling contractor that gets an emergency caller on the phone in one tap, shows the service area, and turns everyone else into a quote request with the details a technician needs.

### 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: emergency banner, hero, services, service area, quote request, reviews, licenses, financing
- `/services` Services: each service with its page
- `/service-area` Service area: towns and ZIP codes served, with a ZIP check
- `/quote` Request a quote: the quote form, step by step
- `/about` About: family story, licenses and insurance, team

Home, top to bottom:
1. Emergency banner across the top: 24/7 emergency service with the phone number.
2. Header: logo, Services, Service area, About, the phone number in red, and Request a quote.
3. Split hero: headline and Call now left, a technician photo right with "Same-day service" chip.
4. Services grid: furnace repair, AC repair, heat pumps, tune-ups, new systems, indoor air.
5. Service area: a list of towns with a ZIP code check.
6. Quote request form preview with the first step.
7. Reviews: three short reviews with first names and towns.
8. Licenses and insurance strip with license numbers, then footer with hours and phone.

Copy to start from, in `content.ts`: headline "No heat? We pick up 24/7.", subcopy "Repairs, tune-ups and new systems across Clark and Madison counties. Licensed, insured, and on time or the visit is free.", primary action "Call now".

### Design system
Mood: Dependable and direct, like a service van with clean lettering: white, a deep navy, a heat red and a cool blue.

Palette: white `#ffffff`, van navy `#0d1b2a`, heat red `#c8300f`, cool blue `#dbe9fb`. Tokens: background `#ffffff`, foreground `#0d1b2a`, primary `#c8300f` with `#ffffff` labels, cards `#f2f5f9`, accent `#dbe9fb`.

Type: Saira Condensed for headlines, the phone number and service names; Encode Sans for body, the quote form and service area. Load both from https://fonts.googleapis.com/css2?family=Saira+Condensed:wght@600;800&family=Encode+Sans:wght@400;600&display=swap.

Corners: 6px on controls, 10px on cards, 14px on large panels. Spacing: Efficient: 64 to 80px between sections, big tap targets.

Imagery: The company’s own technicians and vans, real equipment installs, the service area map; no cartoon thermometers. 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
- Sticky call bar on phones with Call now and Request a quote
- ZIP check: input that says whether the ZIP is in the service area from towns.json
- Multi-step quote form (contact, system, timing) that posts once at the end

Motion:
- ZIP check answers as you type the fifth digit
- The quote form remembers its steps if the visitor goes back

The signature motion is: the hero’s accent shifts from cool blue to heat red as the visitor scrolls, like a thermostat turning up. 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/services.json`: a service: name, summary, signs you need it, what we do, typical time; each has its page at `/services/<slug>`
- `src/content/towns.json`: a town served: name, ZIP codes
- `src/content/reviews.json`: a review: first name, town, text, date, where it was posted

Forms:
- `quote`: A homeowner asks for a quote or a visit. Fields: name, phone, email, ZIP code, service (select), system type (furnace, AC, heat pump, boiler, not sure), age of system, what is happening, preferred visit time.

Linked tools:
- Financing: the lender’s application page, linked from the financing note.
- Reviews: links to the company’s review profiles.

### 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 #0d1b2a on #ffffff 17.39:1; text on cards #0d1b2a on #f2f5f9 15.90:1; secondary text on muted surfaces #4a545f on #ecedee 6.57:1; secondary text on the page #4a545f on #ffffff 7.70:1; label on the primary action #ffffff on #c8300f 5.40:1; label on secondary surfaces #0d1b2a on #f2f5f9 15.90:1; label on the accent #0d1b2a on #dbe9fb 14.13:1; error label #ffffff on #c62f2f 5.45:1; primary action against the page #c8300f on #ffffff 5.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: LocalBusiness with opening hours.

### Guardrails
- Avoid: Cartoon thermometers or snowflakes, "best in town" claims, a chat widget, coupons with expired dates, and hiding the phone number.
- 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