Cobble
Cobble is a site for a paving and driveway contractor: paver driveways, asphalt paving and sealcoating, patios and walkways, Belgian block and cobblestone, permeable pavers, and repair and re-leveling. It is exact, solid and calm, like a landscape architect’s site plan: the home page opens on a photo of a new paver drive seen straight down from above, edge to edge on every screen, easing down slowly like a drone over the drive, with the headline on a paver framed by a border course and the phone number and a free estimate right under it. Cards, photos and buttons have a small square notch cut out of each corner, the faint joints of a herringbone drive run behind every page, and the colours are clinker, asphalt and joint sand on pale limestone. The demo is a fictional business, Kessler Paving & Stone.
Cobble 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) |
| Services, projects, guides, 404 | Pages → the page’s own entry |
| Prices (the price per square foot, packages, a drive going in step by step, booking, deposits and sealing visits, questions) | Pages → Prices page |
| Contact (estimate form, towns, map, hours, details, questions) | Pages → Contact page |
| Services (icon, colour, price from, how long, what’s included, typical jobs, questions, photo) | Content → Services |
| Projects (where, when, what we did, the area, time, cost, the lay sheet, photo, story) | Content → Projects |
| Guides (one can be for members only) | Content → Guides |
| Name, phone, address, insurance, navigation, header button, profiles | Pages → Site settings |
| Buttons, labels, chat, emails, game texts | Content → Interface texts |
| Privacy, terms, warranty | Pages → Legal |
In headlines, words wrapped in *stars* get a course of small pavers laid under them, one by one from the
left, as they scroll into view, as in “Laid this year, *lay sheet and all*”.
The opening photo
Section titled “The opening photo”The home page’s first section is the photo. Its texts are yours: the status line on a joint-sand chip
(“Booking spring installs”), the small line, the headline, the lead, two buttons (make the first one your
phone number as a tel: link and it gets a phone icon) and up to three facts on white pavers under the
paver (wide screens).
- Photo: 16:9 and at least 1920 pixels wide, best taken from straight above (a drone shot of a drive
or a patio). It shows at once and is the page’s largest image. Set Photo focus to the part that
should stay in view on a narrow screen (e.g.
50% 50%).
The copy stands on the paver, an opaque panel (limestone by day, asphalt at night) with notched corners and a border course of soldier pavers round its edge, so it reads the same over any photo. On load the border course is laid round the copy like the hand of a clock and two dimension lines draw out along the top and the right edge; the photo slowly eases down and squares up over the drive, then drifts back. With reduced motion nothing moves.
Services and projects
Section titled “Services and projects”Each service card’s photo is swept clean as the card scrolls into view: a broad, soft-edged sweep crosses it on a slant, like a push broom clearing sand off new pavers; then a band in one of the three colours with its number and its drawing. Projects carry a lay sheet, the spec sheet the crew works from, with the drive’s build-up drawn down its edge (pavers, bedding sand, base, ground) and up to eight lines such as “Pattern: 90° herringbone”, “Base: 8 in, 2A stone, 4 lifts” or “Joints: Polymeric sand, tan”. Cards show the first three lines; the project’s page shows them all beside the story.
Prices, booking and payments
Section titled “Prices, booking and payments”The prices page holds the price per square foot on one big asphalt paver with its small print (tear-out, an apron, the smallest job, the estimate), up to four packages (mark one as the popular one; prices can be ranges like “$11,000–$19,000”), a drive going in step by step beside a drive drawn in plan that is built stage by stage as you scroll (staked out, dug, the base, the screeded sand, the pavers, the border course; also on the home page), booking a free estimate with Cal.com, and deposits and sealing visits you take with Stripe or Lemon Squeezy: each one gets a one-time price id. Without keys, the booking shows a preview of the calendar and the payment buttons explain how to switch them on.
The map of the area
Section titled “The map of the area”The map is drawn from OpenStreetMap in your colours, with a
pin on your yard and a ring for the area you cover. It is part of the page (no embed, no cookies) and
follows the theme and your accent. To draw your own, put your yard’s coordinates in map.config.json and
run pnpm map -- fetch. detail: "area" (the default in Cobble) draws the main roads, railways, water and
woods of a whole district, and Contact page → Map → Radius sets the ring; detail: "streets" draws the
streets and buildings round one address instead.
Integrations
Section titled “Integrations”Everything works without keys; each feature switches on with its variables in .env.example.
| Feature | Where | Service |
|---|---|---|
| Book a free estimate | Prices page, loads on click; a preview of the calendar until connected | Cal.com |
| Deposits and sealing visits | Prices page (one-time prices) | Stripe or Lemon Squeezy |
| Care notes by email | Home and guides pages, with a welcome email | Supabase or Mailchimp |
| Members-only guides | A guide marked members only shows its text after signing in | Clerk |
| Estimate form | Contact page; messages go to the email in Site settings | Resend |
| AI chat | On every page, answers about services, prices, projects and areas; gives prices only as ranges or “from”, never settles property lines, permits or stormwater rules for anyone | Claude or OpenAI |
| Search | ⌘K or the search button: services, projects, guides, prices, contact | built in, or Algolia |
| Analytics | Every page; Google Analytics only after consent | Plausible, Umami, PostHog, Google Analytics |
| Photos | Served from your Cloudinary account when it is set | Cloudinary |
Sections
Section titled “Sections”The home page is built from these sections, in any order: Opening (the photo and the paver), Services (cards swept clean as they scroll in), How a drive goes in (a drive drawn in plan, built stage by stage), Projects (with their lay sheets), Numbers (on pallets of pavers stacked course by course as they scroll in), The area on a map, Guides, Care notes by email and Closing call (an asphalt band with a photo set in a border course of clay soldiers). With reduced motion nothing moves.
Colors and brand
Section titled “Colors and brand”src/content/singletons/brand.json (Pages → Brand in Keystatic) holds three colors: the accent
(clinker: buttons, links, marked words and their courses by day), the second (asphalt: the deep bands,
the plates, the border courses and dark fills, and the night theme) and the third (joint sand: chips, the
status line, light fills and the courses by night). The accent and asphalt are darkened until white text on
them is readable and the joint sand is lightened until dark text on it is; a color that can’t get there stops
the build with a message. Brand also sets the fonts and the corners (notched, a small square cut out of each
corner, or square). The site opens on the limestone day theme even when the visitor’s system is dark; the
toggle switches to asphalt after rain, and the browser remembers the choice. The header strip, the tab bar
and the deep bands look the same in both.
Languages
Section titled “Languages”Cobble is ready for more languages: see Languages.
The 404 page
Section titled “The 404 page”A small game, Running bond: a drive from above on a grid of squares, its bedding sand screeded, a drain grate or a lamp post in the way and the lawn biting into its corners. Pave every square with whole pavers (two squares) and, where you must, halves cut from one, and never let four corners meet at a point: staggered joints are what keep a drive from cracking. Tap a square and then the one beside it to lay a whole paver, or the same square twice to cut a half (or the arrow keys and Enter); tap a paver to lift it, U undoes and R starts over. A point where four corners meet shows a ring. Each drive scores 100 less 25 for every cut over the fewest; the fewest is worked out exactly, and a drive is only dealt when paving it row by row the obvious way needs more cuts or gets stuck. Three drives, each bigger. 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, services, projects and guides for AI assistants, in every language.- Pages carry JSON-LD: the business as a
HomeAndConstructionBusinesswith the areas it serves and its packages (price ranges as a minimum and a maximum), services asServices with their price, projects asCreativeWorks, a drive going in step by step as aHowTo, questions as aFAQPage, and 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).
