Handy
Handy is a site for a handyman or a small home-repair business: odd-job services, property maintenance, flat-pack assembly and “husband for an hour” services. It is set edge to edge on a pegboard: a pale board with rows of holes and the outlines of tools, hi-vis orange, safety yellow and painter’s tape blue, and chunky headings. On the home page a cutaway of a home runs across the whole window and, as you scroll, the jobs on the to-do list get done one by one: the drip stops, the picture levels, the bulb comes on, the shelf straightens, the door stops creaking, and the to-do note ticks them off. The demo is a fictional business, Sorted Handyman Services.
Handy 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, jobs, tips, 404 | Pages → the page’s own entry |
| Prices (hourly rate, packages, how a job works, booking, deposits and vouchers, questions) | Pages → Prices page |
| Contact (quote form, areas, map and its ring, hours, details, questions) | Pages → Contact page |
| Services (tool, price from, how long, what’s included, typical jobs, questions, photo) | Content → Services |
| Jobs (where, when, time, cost, before and after photos, story) | Content → Jobs |
| Tips | Content → Tips |
| 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* get a strip of blue painter’s tape underneath, as in “Your
to-do list, *sorted*”.
The to-do list
Section titled “The to-do list”The home page’s opening has a to-do list of exactly five jobs, in the order the drawing fixes them: a dripping tap, a crooked picture, a dead bulb, a sagging shelf and a squeaky door. Change the words to your own (keep each to the same kind of job, since the drawing doesn’t change), and the title of the note.
Jobs: before and after
Section titled “Jobs: before and after”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.
Prices, booking and payments
Section titled “Prices, booking and payments”The prices page holds your hourly rate on a big price tag with its small print (minimum, call-out, materials, waste), up to four packages (mark one as the popular one), how a job works as steps on a strip of painter’s tape (also on the home page), booking a visit with Cal.com, and deposits and gift vouchers you take with Stripe: 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 you cover
Section titled “The map of the area you cover”The map is drawn from OpenStreetMap in your colors, with a
pin on your base 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 base’s coordinates in map.config.json and run pnpm map -- fetch. detail: "area" (the default in Handy) draws the main roads, railways, water and woods of a district; make
size about four times your radius in each direction (24,000 × 12,000 m for 5 km). 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 visit | Prices page, loads on click; a preview of the calendar until connected | Cal.com |
| Deposits and gift vouchers | Prices page (one-time Price ids) | Stripe |
| Tips by email | Home and tips pages, with a welcome email | Supabase |
| Quote 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 gives safety advice on gas or electrics | Claude |
| Search | ⌘K or the search button: services, jobs, tips, prices, contact | built in, or Algolia |
| Analytics | Every page; Google Analytics only after consent | Plausible, Umami, Google Analytics |
Sections
Section titled “Sections”The home page is built from these sections, in any order: Your to-do list (the opening), Services (cards that swing in on pegboard hooks), Recent jobs (before and after), How a job works (steps on a strip of tape that unrolls), Numbers (on a tape measure that pulls out), The area covered (the map), Tips, Tips by email and Closing call (a safety-yellow band between strips of caution tape). With reduced motion, the home stands fixed and ticked off and nothing moves.
Colors and brand
Section titled “Colors and brand”src/content/singletons/brand.json (Pages → Brand in Keystatic) holds three colors: the accent
(hi-vis orange: buttons, marks, the ticks), the second (safety yellow: the to-do note, the price
tag, the tape measure) and the third (painter’s tape blue). 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 fonts and the corners. The site opens in the
day theme even when the visitor’s system is dark; the toggle switches to the night, a charcoal board,
and the browser remembers the choice.
Languages
Section titled “Languages”Handy is ready for more languages: see Languages.
The 404 page
Section titled “The 404 page”A small game, Screw it: drive each screw into a plank until its head sits flush, with circles of your finger or mouse round it or the arrow keys, then press “That’s flush” (or Enter). Stop short and it sticks out; one turn too many and the thread strips. Every screw has its own thread, so watch the head, not the turns. Three planks of five screws; 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, jobs and tips for AI assistants, in every language.- Pages carry JSON-LD: the business as a
HomeAndConstructionBusinesswith the areas it serves and its packages, services asServices with their price, jobs asCreativeWorks, how a job works as aHowTo, questions as aFAQPage, and each tip 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).