Skip to content

Slate

Slate is a site for a roofer or a roofing company: slaters and tilers, flat-roof specialists, leadworkers, gutter and fascia firms, chimney repair. It is drawn like a set of architect’s sheets under a sky that changes as you scroll: hairline cards, dimension lines, labels in a mono, a fine serif for headings, slate grey with weathered copper (verdigris), copper and sky blue. On the home page a house is drawn in cross-section and, as you scroll, its roof is built layer by layer: the rafters rise, the membrane rolls out, the battens snap on, the slates are laid course by course from the eaves up, the ridge goes on, the flashing is dressed round the chimney and the gutters are fixed. Then a storm rolls in, rain falls, and the water runs off the slates into the gutter and down the pipe while the room underneath stays dry, with the fire and the lamp lit. The demo is a fictional firm, Hale & Ridge Roofing.

Slate comes in two variants, chosen when you create the site: files/Sanity (static pages, any host) and EmDash (--cms emdash, rendered on request on Cloudflare). The pages are the same in both.

Page Edit it in
Home Pages → Home page (a list of sections)
Services, jobs, advice, 404 Pages → the page’s own entry
Prices (the survey, typical jobs and prices, how a job works, booking, reports and deposits, questions) Pages → Prices page
Contact (survey form, areas, map and its ring, hours, details, questions) Pages → Contact page
Services (icon, price from, how long, what’s included, typical jobs, questions, photo, colour) Content → Services
Jobs (where, when, time, cost, before and after photos, story) Content → Jobs
Advice (one can be members only) Content → Advice
Name, phone, address, insurance, navigation, header button, profiles Pages → Site settings
Buttons, labels, chat, emails, game texts Content → Interface texts
Privacy, terms, guarantee Pages → Legal

In headlines, words wrapped in *stars* are set in the accent with a dimension line under them, as in “A roof that keeps *the weather out*”.

The home page’s opening (the Roof section) has eight captions, one per layer, in the order the drawing builds them: rafters, membrane, battens, slates, the ridge, the flashing, the gutters and the storm. Change the words to your own (keep the order, since the drawing doesn’t change), the pitch written beside the eaves and the scroll hint. With reduced motion, or in a browser without scroll-driven animations, the finished roof stands in the rain with the last caption.

Each job has a before and an after photo of the same view. On the cards (home page, jobs page, a service’s page) the after photo wipes in as the card scrolls past; on the job’s own page a slider lets visitors compare them (drag, or the arrow keys). Take both photos from the same spot.

The prices page holds the survey set large (free, in the demo) with its small print, up to four typical jobs with their prices (mark one as the most asked-for), how a job works as steps up a ladder (also on the home page), booking a survey with Cal.com, and survey reports and deposits paid online with Stripe or Lemon Squeezy: each one gets a one-time Price id (or a Lemon Squeezy variant id). Without keys, the booking shows a preview of the calendar and the payment buttons explain how to switch them on.

The map is drawn from OpenStreetMap in your colors, with a pin on your yard and a dashed ring for the area you cover (Contact page → Map → Radius, in km; 0 hides it). It is part of the page (no embed, no cookies) and follows the theme and your accent. To draw your own area, put your yard’s coordinates in map.config.json and run pnpm map -- fetch. detail: "area" (the default in Slate) draws the main roads, railways, water and woods of a district; make size about four times your radius in each direction (30,000 × 15,000 m for 8 km). detail: "streets" draws the streets and buildings round one address instead.

Everything works without keys; each feature switches on with its variables in .env.example. See Features for each service.

Feature Where
Book a survey Prices page, loads on click; a preview of the calendar until connected (Cal.com)
Survey reports and deposits Prices page (Stripe or Lemon Squeezy)
Roof care by email Home and advice pages, with a welcome email (Supabase or Mailchimp)
Survey form Contact page; messages go to the email in Site settings (Resend)
AI chat On every page, answers about services, prices, jobs and areas; never tells anyone to go up on a roof (Claude or OpenAI)
Members-only advice An article marked “Members only” shows its text to signed-in members (Clerk)
Search ⌘K or the search button: services, jobs, advice, prices, contact (built in, or Algolia)
Analytics Every page; Google Analytics only after consent (Plausible, Umami, PostHog, Google Analytics)
Photos Served from Cloudinary when a cloud name is set

The home page is built from these sections, in any order: the Roof (the opening), Services (cards cut like slates, laid in courses), Recent jobs (before and after), How a job works (steps up a ladder), Numbers (along a dimension line), The area covered (the map), Advice, Roof care by email and the Closing call (a storm band with rain falling past the photo).

src/content/singletons/brand.json (Pages → Brand in Keystatic) holds three colors: the accent (verdigris: buttons, links, marks, the flashing), the second (copper: a warm fill, the chimney pots, the warm room) and the third (sky: the sky behind the page, rain, a cool fill). Buttons are darkened until their white text is readable, the second and third are lightened until ink text on them is; a color that can’t get there stops the build with a message. Brand also sets the three fonts (headings, text, labels) and the corners. The site opens in the day theme even when the visitor’s system is dark; the toggle switches to the night sky, and the browser remembers the choice.

Slate is ready for more languages: see Languages.

A small game, Leak hunt: a roof of slates hides a few cracked ones. Lift a slate (tap, or the arrow keys and Enter): a sound one shows how many cracked slates touch it, and since the slates are laid with their joints broken, each one touches six. Lift a cracked one and the rain gets in, which costs a bucket. Mark the slates you suspect (the Mark switch, a right-click, a long press or F). Three roofs, more cracked slates each, three buckets for the whole game; the first slate on each roof is always sound. The best score is kept in the visitor’s browser.

  • AGENTS.md describes the project for coding assistants (Claude Code reads it through CLAUDE.md, Cursor through .cursor/rules/).
  • /llms.txt lists your pages, services, jobs and advice for AI assistants, in every language.
  • Pages carry JSON-LD: the business as a HomeAndConstructionBusiness with the areas it serves and its typical jobs, services as Services with their price, jobs as CreativeWorks, how a job works as a HowTo, questions as a FAQPage, and each article as a BlogPosting.
Terminal window
pnpm dev # local site, editor at /keystatic
pnpm build # production build
pnpm map -- fetch # draw the map round map.config.json from OpenStreetMap
pnpm cms sanity schema|seed # move content to Sanity (see Content → Sanity)

In the EmDash variant: npm run dev, npm run deploy (Cloudflare) and npm run emdash:schema (after changing the content model).