Skip to content

Flume

Flume is a site for a plumber: emergency repairs, drain cleaning, water heaters, repiping, leak detection and fixtures for homes. It is cinematic and calm, built from one picture: copper and clear water under a hard raking light on a dark ground. The home page opens on a short silent film of water running along a copper channel, edge to edge on every screen, with the phone number and a free quote right on it. Behind every page the net of light that water throws on the floor of a basin drifts as you scroll; the colours are water cyan, copper and clear aqua on a cool porcelain white. The demo is a fictional business, Tidewell Plumbing & Drain.

Flume 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, guides, 404 Pages → the page’s own entry
Prices (trip fee, packages, how a visit works, booking, deposits and vouchers, questions) Pages → Prices page
Contact (quote form, towns, map, hours, details, questions) Pages → Contact page
Services (icon, badge colour, price from, how long, what’s included, typical jobs, questions, photo) Content → Services
Jobs (where, when, called, on site in, time, cost, photo, story) Content → Jobs
Guides (one can be for members only) Content → Guides
Name, phone, address, license, 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* fill with water as they scroll into view and stay in the water colour, as in “Water where you want it. *Nowhere else.*”.

The home page’s first section is the film. Its texts are yours: the status line (“On call now”), 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 under them. The picture is two files:

  • Photo: the film’s first frame, 16:9 and at least 1920 pixels wide, dark at the top where the text sits. It shows at once and is what search engines and slow phones see. Set Photo focus to the part that should stay in view on a narrow screen (e.g. 50% 60%).
  • Film: a short silent MP4 loop in public/media/ (about 2 MB, 1280 wide), e.g. /media/hero.mp4. It starts loading only after the page has, fades in over the photo and pauses when you scroll past. Leave it empty to show the photo only. Visitors who prefer reduced motion or save data see the photo.

A dark scrim under the text keeps it readable over the brightest frame; if you swap in a much brighter film, check that the text still reads.

Each service has a round badge in one of the three colours: water cyan, copper (keep it for the emergency service) or clear aqua. Jobs are shown as service tickets: when the call came in, how soon you were on site, the time on site and the cost, with a “Fixed” stamp.

The prices page holds your trip fee on a disc of water with its small print (evenings, nights, how the repair is priced), up to four packages (mark one as the popular one), how a visit works as steps along a copper pipe that fills with water (also on the home page), booking an estimate with Cal.com, and deposits and gift vouchers 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 is drawn from OpenStreetMap in your colours, with a pin on your shop 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 shop’s coordinates in map.config.json and run pnpm map -- fetch. detail: "area" (the default in Flume) 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.

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

Feature Where Service
Book an estimate Prices page, loads on click; a preview of the calendar until connected Cal.com
Deposits and gift vouchers Prices page (one-time prices) Stripe or Lemon Squeezy
Guides 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
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; tells anyone with a leak to shut off the main and call, and never gives instructions for gas or permit work Claude or OpenAI
Search ⌘K or the search button: services, jobs, 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

The home page is built from these sections, in any order: Opening (the film), Services (cards with a round badge), How a visit works (a copper pipe that fills with water), Recent jobs (service tickets), Numbers (on pressure gauges whose needles sweep up), The area on a map, Guides, Guides by email (a panel of deep water that fills as it scrolls in) and Closing call (a band of deep water with a photo standing in it). With reduced motion nothing moves.

src/content/singletons/brand.json (Pages → Brand in Keystatic) holds three colors: the accent (water cyan: buttons, links, the water in drawings and marked words), the second (copper: the pipes, numbers and the emergency service) and the third (clear aqua: highlights and small fills). The accent and copper are darkened until white text on them is readable, aqua 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 (rounded with pill buttons, or nearly square). The site opens on the porcelain day theme even when the visitor’s system is dark; the toggle switches to the night, and the browser remembers the choice. The header strip, the tab bar and the deep-water bands look the same in both.

Flume is ready for more languages: see Languages.

A small game, Rough-in: a wall is open between floors, with the water main on the left and three to five fixtures across it. Lay pipe bay by bay (tap or drag, or the arrow keys and Enter) so one run feeds every fixture from the main, branching where you like; a stud can’t be passed and a joist costs two bays. Then open the valve: if every fixture gets water, the wall scores 100 × the cheapest possible run ÷ yours (the cheapest run is worked out exactly for every wall). Three walls, bigger each time; 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 guides for AI assistants, in every language.
  • Pages carry JSON-LD: the business as a Plumber with the areas it serves and its packages, services as Services with their price, jobs as CreativeWorks, how a visit works as a HowTo, questions as a FAQPage, and each guide 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).