Lodge
Lodge is a site for a boutique hotel: a small hotel, a guesthouse, a B&B, a few apartments with a front desk. The home page opens on the reception, a picture that fills the window and that the camera walks up to as you scroll (in the evening, with the lamp lit, in the dark theme). The rooms hang as keys on the board: point at one, focus it or tap it, and its enamel tag turns over to show the room, its price and the button to book. The concierge’s picks around the hotel come as postcards, each with a stamp showing the minutes on foot from the door and a tip written by hand. Cobalt, saffron and pink on a faint pattern of old floor tiles, headings in a warm, round serif. The demo is a fictional hotel in El Born, Barcelona, Casa Safrà.
Lodge 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.
Your city
Section titled “Your city”The template draws the map itself, so it can be any city:
- Set the area in
map.config.json:areawith its south, west, north and east edges in degrees (right-click on openstreetmap.org → “Show address” gives you a point’s latitude and longitude). About 2 km across works best, with the hotel near the middle. - Run
npm run map -- fetch. It downloads the area from OpenStreetMap (one request, up to a minute), builds the map’s geometry and the walkable streets insrc/data/map/and draws four base maps intopublic/map/: the city in 3D and as a plan, each by day and at night. A city on the sea is mapped only by its coastline; the map command closes it into water. - Put the hotel in Pages → The map (
building: its name, latitude and longitude). Give your places their latitude and longitude and your walks their route. The minutes on foot are measured along the real streets when the site builds, at 80 metres a minute, so they are never typed by hand.
Map data is © OpenStreetMap contributors, under the Open Database License. Every map shows the attribution; keep it.
Pages and their content
Section titled “Pages and their content”| Page | Edit it in |
|---|---|
| Home | Pages → Home page (a list of sections; the reception’s two pictures are in its first section) |
| Rooms (a filter by guests, the rooms with their price and features, booking, groups and events) | Pages → Rooms page and Content → Rooms |
| Nearby (every place on the map, a filter by kind, the minutes from the hotel) | Pages → Neighbourhood page and Content → Places |
| A place (what it is, the concierge’s tip, nearby on the map) | Content → Places |
| Walks (every walk on the city) and a walk (on the plan, place by place with its minute) | Pages → Walks page and Content → Walks |
| Journal | Pages → Journal page and Content → Journal |
| Visit (the hotel and the nearest places on the plan, directions, check-in, the contact form, questions) | Pages → Visit page |
| Name, city, contact, navigation | Pages → Site settings |
| The hotel and district names on the map | Pages → The map |
In headlines, words wrapped in *stars* sit on a band of saffron, like a stroke of paint.
Rooms and booking
Section titled “Rooms and booking”Each room has how many it sleeps, its size, bed, view, price and a note (e.g. “a night, breakfast included”), features, a few words and a picture. On the home page the rooms hang as keys, numbered in order; the rooms page lists them with a filter by guests. Turn on “Book online” and add a Stripe Price id (or a Lemon Squeezy variant id) for the deposit, and the room’s button takes guests to checkout; after paying they get an email and come back to the rooms page with a message. Groups and events book a call with Cal.com.
Integrations
Section titled “Integrations”Everything works without keys; each feature switches on with its variables in .env.example.
| Feature | Where | Service |
|---|---|---|
| Booking (deposit) | Rooms page and the keys on the home page | Stripe or Lemon Squeezy |
| Groups and events | Rooms and walks pages, loads on click | Cal.com |
| Newsletter | Home and journal pages, with a welcome email | Supabase or Mailchimp |
| Contact form | Visit page; messages go to the email in Site settings | Resend |
| AI chat | Every page; answers from your rooms, places (with their minutes), walks, visit details and journal | Claude or OpenAI |
| Search | ⌘K or the search button: rooms, places, walks, journal, visit | built in, or Algolia |
| Analytics | Every page; Google Analytics only after consent | Plausible, Umami, Google Analytics, PostHog |
| Members-only posts | Journal | Clerk |
Sections
Section titled “Sections”The home page is built from these sections, in any order: The reception (the signature: the camera walks up to the key wall as you scroll), Rooms (the keys on the board), Numbers, Nearby (the concierge’s postcards), Walks, Journal, Newsletter and a closing call over a photo from edge to edge.
Colors and brand
Section titled “Colors and brand”src/content/singletons/brand.json (Pages → Brand in Keystatic) holds three colors: the accent
(cobalt: buttons, the key tags, pins and walks), the second (saffron: the rims of the tags, the band
under marked words, the line under buttons, the stamps) and the third (pink: soft fills and tags).
Buttons are darkened until their white text reads; every color is adjusted for each theme, and one that
can’t get there stops the build with a message. Brand also sets the fonts (text, headings, labels) and
the corners; the hand on the postcards is Caveat. The theme follows the system, day or night, unless the
visitor picks one with the toggle; the pictures and maps switch with it.
Languages
Section titled “Languages”Lodge is ready for more languages: see Languages.
The 404 page
Section titled “The 404 page”A small game, Finish the tile: a Barcelona floor tile is half or a quarter painted, and you paint the rest so the pattern is whole. On the first tile the right half mirrors the left, on the second every quarter mirrors its neighbour, on the third every quarter is the painted one turned a quarter round. Tap a square to change its colour (or arrows, 1–3 for a colour and Enter to fire the tile); each tile scores 100 × the squares painted right ÷ the squares to paint. 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, walks and places for AI assistants, in every language.- Pages carry JSON-LD: the hotel as a
Hotelwith itsHotelRooms and their prices, walks asTouristTrips, places asTouristAttractions, questions as aFAQPage, posts asBlogPostings.
Commands
Section titled “Commands”pnpm dev # local site, editor at /keystaticpnpm map # draw your city (npm run map -- fetch | build | render)pnpm 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).
