Ember
Ember is a site for campsites, glamping sites, caravan parks and cabin stays, set like a national-park field guide: map paper with topographic contour lines, photos mounted as numbered plates, trail-blaze colors and round passport stamps. It has your stays (each with its own page and a deposit to hold the dates), the camp with an illustrated map whose trail draws itself, field notes and a visit page with directions.
Ember 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) |
| Stays, camp, field notes, visit, 404 | Pages → the page’s own entry |
| Stays (pitches, tents, cabins) | Content → Stays |
| Field notes | Content → Field notes |
| Camp name, email, phone, place, coordinates, season, navigation, header button, profiles | Pages → Site settings |
| Buttons, labels, chat, search, emails, game texts | Content → Interface texts |
| Privacy, terms | Pages → Legal |
Stays marked Featured come first, then by Order. Each stay has a kind (“Tent pitch”, “Cabin”), a price as shown and what it is per, how many it sleeps, its size, where it is on the map, what’s there, an optional stamp (Badge), a color for its trail blaze and a photo. Field notes pick a color too.
In headlines, words wrapped in *stars* get a painted trail-blaze underline, as in
“Pitch your tent where the *lake* begins”.
The camp map
Section titled “The camp map”The camp page (Pages → Camp page → Camp map) holds an illustrated map of your camp (3:2, without text) and its places: each has a name, a line of text, a color and a position in percent from the left and top of the picture. The places are numbered in their order, shown as pins on the map and listed in the legend beside it, and a dashed trail walks from pin to pin. In browsers with scroll-driven animations the trail draws itself and the pins pop up as the map scrolls into view; other browsers, and visitors who prefer reduced motion, see the whole trail. It needs no JavaScript. The home page shows the same map with its Camp map section.
The camp page also has your story with a photo, numbers and the camp code (house rules).
Booking and deposits
Section titled “Booking and deposits”Every stay page has a Hold your dates button. With a Stripe Price id on the stay (a one-time price: the deposit), it takes the deposit with Stripe Checkout; the guest then confirms the dates by email. If you already use a booking system, put its link in the stay’s Booking link and the button opens it instead. Fully booked hides the button.
The visit page
Section titled “The visit page”An illustrated map of the area with a pin (placed in percent), your address and arrival details. Add your latitude and longitude (Pages → Visit page → Map) and the page also offers directions (Google Maps, in a new tab) and a live OpenStreetMap, which loads only when the visitor opens it. Below: a contact form and booking activities (canoe hire, a guided walk…) with Cal.com.
Integrations
Section titled “Integrations”Everything works without keys; each feature switches on with its variables in .env.example.
| Feature | Where | Service |
|---|---|---|
| Deposits | Stay pages: a button per stay with a Stripe Price id (one-time) | Stripe |
| Contact form | Visit page; messages go to the email in Site settings | Resend |
| Book an activity | Visit page, loads on click | Cal.com |
| Newsletter | Home and field notes pages, with a welcome email | Supabase |
| Ask the warden | Chat on every page, answers from your stays, questions, camp map and code, and field notes | Claude |
| Search | ⌘K or the search button: stays, field notes, camp, visit | built in, or Algolia |
| Analytics | Every page; Google Analytics only after consent | Plausible, Umami, Google Analytics |
After a deposit is paid, the Stripe webhook (/api/stripe/webhook) emails the guest; add your
own steps there, such as noting the booking in your calendar.
Sections
Section titled “Sections”The home page is built from these sections, in any order: Hero (a photo plate with a season stamp and a strip of facts), Stays, Camp map, A day at camp (moments from morning to the campfire, under a strip of sky the sun crosses as you scroll), Numbers, Latest field notes, Newsletter sign-up and Closing call to action (a night panel with a campfire).
Colors and brand
Section titled “Colors and brand”src/content/singletons/brand.json (Pages → Brand in Keystatic) holds three trail colors: the
accent (buttons, the trail-blaze underline, markers) and a second and third color for
markers, pins and panels (the newsletter is in the second, the camp code in the third). Text on
a color is always ink, so each color is lightened until it is readable; a color that can’t get
there stops the build with a message. The map paper, links and the night theme (the woods at
night, with an ember glow) are derived from them. Brand also sets the fonts (text, headings,
code) and the corners (square like a printed guide, or slightly rounded).
Languages
Section titled “Languages”Ember is ready for more languages: see Languages.
The 404 page
Section titled “The 404 page”A small game, Follow the stars: lost in the woods at night, watch the stars light up one after another, then follow them in the same order (click or tap them, or press 1–7). Each round adds a star; a wrong star ends the game and shows the way you came. 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/), including what makes the look./llms.txtlists your pages, stays and field notes for AI assistants, in every language.- Pages carry JSON-LD: the campground with its amenities, each stay with its price and occupancy, the booking questions and each note.
Commands
Section titled “Commands”pnpm dev # local site, editor at /keystaticpnpm build # production buildpnpm 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).