Tiny Town
Tiny Town is a site for a place with many parts on one map: a new neighbourhood or regeneration project, a coworking campus, a market hall or shopping street, a town or village, a university or holiday park. It’s made like a building-block diorama: an isometric town, drawn from your own layout in your brand’s colours, builds itself as you scroll and flies to each district; places are pinned on the map; homes, workspace passes, what’s on, news and a visit page complete it. It runs from edge to edge of the window.
Tiny Town 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) |
| Places, homes, workspace, what’s on, news, visit, 404 | Pages → the page’s own entry |
| The map’s districts | Pages → The town |
| Places (with their pins) | Content → Places |
| Homes | Content → Homes |
| Events | Content → What’s on |
| News posts | Content → News |
| Name, description, email, address, navigation, header button, profiles | Pages → Site settings |
| Buttons, labels, chat, search, emails, game texts | Content → Interface texts |
| Privacy, terms | Pages → Legal |
In headlines, words wrapped in *stars* get a park-green highlight, as in “A whole *quarter*”.
The map
Section titled “The map”The town is drawn by the template from src/data/town.ts: the baseboard’s size, water, green
and paving areas, and every building as a block (position and size in tiles, height, a paint:
brick, paper, canal, park or ink, rows of windows, a glass roof), with bridges, trees and boats.
Change it to draw your own place; it’s coloured from your brand, and windows light up in the dark
theme.
Pages → The town lists the districts, each with a key, a name and its position on the map in
percent. The home page’s town section has chapters that each fly to a district; places and homes
name their district too, and each place has a pin (percent of the map) for the places page
and its own page. townPoint(x, y, z) in town.ts gives you the percentages of a tile.
On the home page the town builds itself block by block as you scroll, then the camera flies to each chapter’s district while its card scrolls past. Visitors who prefer reduced motion see the finished town.
Places, homes and passes
Section titled “Places, homes and passes”- Places have a kind (the places page filters by it), a summary, address, hours, district, pin, a square picture and a colour; featured ones come first on the home page.
- Homes have a kind, size, price, status (available, reserved or sold), features and a picture; each page offers a viewing with Cal.com. The homes page also has register interest for new homes (a sign-up list in Supabase with a welcome email).
- Passes (Pages → Workspace page): a pass with Sell with Stripe Checkout turned on and a
one-time Price id gets a working button; customers come back to the workspace page and get an
email from the Stripe webhook (
/api/stripe/webhook), where you can add your own steps.
Integrations
Section titled “Integrations”Everything works without keys; each feature switches on with its variables in .env.example.
| Feature | Where | Service |
|---|---|---|
| Passes | Workspace page | Stripe |
| Viewings | Homes and home pages, loads on click | Cal.com |
| Register interest | Homes page, with a welcome email | Supabase |
| Newsletter | Home and news pages, with a welcome email | Supabase |
| Contact form | Visit page; messages go to the email in Site settings | Resend |
| AI chat | On every page, answers from your places, homes, workspace, events, visit page and news | Claude |
| Search | ⌘K or the search button: places, homes, events, news, workspace, visit | 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: The town (builds itself, then flies to each chapter’s district), Places, Homes, What’s on, Numbers, Latest news, Newsletter sign-up and Closing call (a picture 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 is brick (buttons, roofs, pins), the second the canal (water, cool fills), the
third the park (grass, highlights, selected states). Buttons are darkened until their white
text is readable, the second and third are lightened until dark text on them is; a color that
can’t get there stops the build with a message. The paper, ink and the dusk theme are derived
from them. Brand also sets the fonts (text, headings, and the mono font for labels and
addresses) and the corners (round like toy blocks, or softer).
Languages
Section titled “Languages”Tiny Town is ready for more languages: see Languages.
The 404 page
Section titled “The 404 page”A small game, Deliver it: three addresses light up on a grid of streets; drive the delivery van corner by corner (arrow keys, the on-screen arrows, or tap the next corner) past all of them and back to the depot. The fewer streets you drive, the more points; five rounds, and 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 how to draw the map./llms.txtlists your pages, places, homes and news for AI assistants, in every language.- Pages carry JSON-LD: the quarter as a
Place, places asLocalBusinesses, events, the questions on the visit page, and each post.
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).