Keystone
Keystone is a site for an independent estate and letting agent; it also fits property developers (a scheme’s homes as listings) and luxury realtors. It is set at blue hour: deep ink blue with the faint lines of an architect’s floor plan behind every page, front-door green, brass and a red “Sold” strap, a tall serif and a glass pill nav. The home page opens on one house, photographed from across the street and sold as you scroll, with the rating, the headline, one line, Book a free valuation and Browse homes over it from the first frame. The demo is a fictional agency, Calder & Finch.
Keystone 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.
Pages and their content
Section titled “Pages and their content”| Page | Edit it in |
|---|---|
| Home | Pages → Home page (a list of sections) |
| Buy & rent (every home on the market, with filters) | Pages → Properties page |
| A home (photos, price, numbers, highlights, description, key facts, rooms, floor plan, energy rating, map, viewing, enquiry, holding deposit) | Content → Properties |
| Sold & let (results and what they add up to) | Pages → Sold & let page; the homes are Content → Properties with the status Sold or Let agreed |
| Valuation (what you look at, fees, booking, the valuation form, questions) | Pages → Valuation page |
| Areas, and an area guide each (facts, what it’s like, the guide, homes there now) | Pages → Areas page, Content → Areas |
| Guides | Content → Guides (one can be for clients only) |
| About (story, team, how you work) | Pages → About page |
| Contact (the map, hours, visiting, message form, questions) | Pages → Contact page |
| Name, phone, address, area covered, currency, rating, hours, navigation, profiles, memberships | Pages → Site settings |
| Buttons, labels, filters, boards, chat, emails, game texts | Content → Interface texts |
| Privacy, terms, fees | Pages → Legal |
In headlines, words wrapped in *stars* are set in italic and lit like a window at dusk, as in
“Every home has its *evening*”.
Properties
Section titled “Properties”Each home is one entry in Content → Properties: for sale or to let, its status (available, under offer, sold, let agreed), the price in whole units (the asking price, or the rent a month) with an optional qualifier (“Guide price”, “Offers over”), the type, bedrooms, bathrooms, receptions and size in square feet, a summary, highlights, key facts, the rooms with their sizes, the main photo and more photos, a floor plan (any drawing), the energy rating in SAP points (the chart is drawn from them), where it is (latitude and longitude: the street, not the door) and the description as the body. Sold and let homes move to Sold & let and show what they achieved (for example “+4% over asking” and the days on market).
Cards carry the agent’s board (For sale, To let, Under offer) and the results a red strap; the main
photo morphs into the home’s page. The listing page’s filters (buy or rent, a price range, bedrooms and
the area) run in the browser and keep themselves in the address, so a filtered list can be shared:
/properties?market=rent&max=1500. The price steps are in Interface texts → Properties.
Each home is a schema.org Offer for search engines, its item a SingleFamilyResidence or an
Apartment with rooms, size, address and coordinates.
The hero
Section titled “The hero”The hero is the site’s signature. Four photos of the same house from exactly the same spot (Pages → Home page → Hero → Photos) are revealed one after another as you scroll, while the camera makes a slow approach:
- On the market: the house at blue hour, lights off. It is there from the first frame and is the page’s largest image, so it loads first.
- The door opens: a blade of warm light widens from the front door as the hall comes on.
- Lights on: lamplight blooms from the living room and the library window.
- Sold: the street lamps strike, every window glows, moths circle the lamps and a red “Sold” strap is laid across the board.
Evening haze drifts along the street throughout. The board’s words are text over the photo (Hero → The board in the garden), so you can change and translate them; its position is Hero → Where the board is in the photos, in percent. A readout counts what mattered (asking price, viewings booked, days on market, over asking) and the captions follow in a glass card with a progress line; write your own in the hero’s four stages. The later photos load after the page has loaded. With reduced motion, or in a browser without scroll-driven animations, the hero is one still: the house sold, every light on, with the four stages listed under it.
To use your own house, take four photos from a tripod with a blank board in the garden, or generate one
and edit it into the other three so nothing moves. The positions of the window glows and the street
lamps are at the top of src/components/sections/Hero.astro, in percent of the photo.
Viewings, valuations, enquiries and deposits
Section titled “Viewings, valuations, enquiries and deposits”Book a viewing and book a valuation use Cal.com (PUBLIC_CALCOM_LINK, and
PUBLIC_CALCOM_VALUATION_LINK for a separate valuation event); they load on click, and until they’re
connected the page shows a preview of the calendar with your times. Enquiries on a home’s page go to the
email in Site settings with the home’s name in the subject; the valuation form adds the address, type,
bedrooms and selling or letting. A home to let can take a holding deposit with Stripe (a one-time Price
id) or Lemon Squeezy (a variant id) in its Holding deposit fields.
The map
Section titled “The map”The contact page and the home section “The office” show the streets round your office, drawn from
OpenStreetMap in your colors, with a pin, your address and
directions links; each home’s page shows the same map closer in, centred on that home. It is part of the
page (no embed, no cookies) and follows the theme and your accent. To draw your own, put your office’s
coordinates in map.config.json and run pnpm map -- fetch; keep your homes inside its area.
Integrations
Section titled “Integrations”Everything works without keys; each feature switches on with its variables in .env.example.
| Feature | Where | Service |
|---|---|---|
| Book a viewing, book a valuation | Each home’s page, the valuation page; a preview of the calendar until connected | Cal.com |
| Holding deposit | Homes to let | Stripe or Lemon Squeezy |
| Property alerts | Home, guides and area pages, with a welcome email | Supabase or Mailchimp |
| Enquiries, valuation requests, messages | Home pages, valuation and contact pages; to the email in Site settings | Resend |
| AI chat | Every page; answers about the homes, results, fees, valuations and areas; never values a home itself | Claude or OpenAI |
| Clients-only guide | Guides | Clerk |
| Search | ⌘K or the search button: homes, areas, guides, pages | built in, or Algolia |
| Analytics | Every page; Google Analytics only after consent | Plausible, Umami, Google Analytics, PostHog |
| Photos | Production builds | Cloudinary (optional) |
Sections
Section titled “Sections”The home page is built from these sections, in any order: Hero, Featured homes, How we sell (a photo held beside the steps while a brass line is drawn down them), Recent results (a band of blue hour), The year in numbers (a ruled ledger whose brass rules draw in), Free valuation (the photo revealed through a front door that swings open), Area guides, Latest guides, Property alerts (a terrace whose windows light up one by one), The office (the map) and Closing call.
Colors and brand
Section titled “Colors and brand”src/content/singletons/brand.json (Pages → Brand in Keystatic) holds three colors: the accent
(front-door green: buttons, marks, pins), the second (brass: small capitals, rules, lit words and the
glow of windows) and the third (sold red: the Sold and Let agreed straps, badges). Buttons and the
red are darkened until their white text is readable, brass is adjusted for each theme; a color that
can’t get there stops the build with a message. Brand also sets the fonts and the corners. The site
opens at blue hour even when the visitor’s system is light; the toggle switches to the day (brochure
paper and navy ink) and the browser remembers it. The energy rating’s bands keep their usual colors.
Languages
Section titled “Languages”Keystone is ready for more languages: see Languages. Prices are written in the page’s language with the currency symbol from Site settings.
The 404 page
Section titled “The 404 page”A small game, Asking price: three homes on a street have sold, with their bedrooms, size, garden, parking, condition and price. Set the asking price for a fourth with the slider (or ← → , Shift for bigger steps) and list it. It sells at the price the street’s evidence points to; within 2% earns 100 points, 25% or more off earns nothing. Priced too high it sits on the market, too low it goes in days. Five homes; the best score is kept in the visitor’s browser.
AI assistants and search engines
Section titled “AI assistants and search engines”AGENTS.mddescribes the project for coding assistants (Claude Code reads it throughCLAUDE.md, Cursor through.cursor/rules/)./llms.txtlists your pages, homes, results, areas and guides for AI assistants, in every language.- Pages carry JSON-LD: the agency as a
RealEstateAgent(the area it serves, hours, rating, team), the homes asOffers of aSingleFamilyResidenceorApartment(and anItemListon the listing page), areas asPlaces, questions as aFAQPageand each guide as aBlogPosting.
Commands
Section titled “Commands”pnpm dev # local site, editor at /keystaticpnpm build # production buildpnpm map -- fetch # draw the map round map.config.json from OpenStreetMappnpm 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).