Crema
Crema is a site for a specialty coffee roastery with a café: roasters with a bar, independent coffee shops, and roasters who sell beans online by the bag and by subscription, and to cafés and offices. It is set in a dark roastery: the brown of a roast with the faint grid of a roast-profile chart behind every page, roast copper, crema gold and green bean, a warm serif and a glass pill nav. The demo is a fictional roastery, Ostler, in an old granary on a canal wharf.
The first screen is the roast itself. As you scroll, a tray of green coffee in the roaster turns gold, cracks, darkens to a glossy medium roast and ends as an espresso in the same spot, with a probe counting the bean temperature, a roast curve drawing itself and the five steps in a glass card. The headline, one line, Shop beans, Visit the café and the rating stay over it from the first frame.
Crema 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) |
| Coffees (every coffee, shipping, subscription plans, questions) | Pages → Coffees page |
| A coffee (a page each: story, origin, roast, tasting notes, brew guide, a bag or a subscription, questions, photo) | Content → Coffees |
| The café (on the grinders, the menu with prices and dietary marks, allergens, hours, the room) | Pages → Café page |
| Journal (brew guides and stories) | Content → Journal (one post can be members-only) |
| Wholesale (what you supply, prices per kilo, how it works, a cupping call, an enquiry form, questions) | Pages → Wholesale page |
| Visit (map, hours, getting here, message form, questions) | Pages → Visit page |
| Name, phone, address, rating, opening hours, navigation, profiles | Pages → Site settings |
| Buttons, labels, chat, emails, game texts | Content → Interface texts |
| Privacy, terms, shipping and returns | Pages → Legal |
In headlines, words wrapped in *stars* are set in italic with a line of copper poured along under
them, as in “Roasted on the wharf, *poured slow*”.
The roast (the hero)
Section titled “The roast (the hero)”The hero pins five photos of the same roaster, taken from exactly the same spot: green beans, yellowing, first crack, the finished roast and the cup. As you scroll, each is revealed into the last behind a glowing seam: heat rises from the tray, first crack bursts out from the middle with chaff and smoke, the roast sweeps in from the lamp’s side, and the espresso clears out of the steam. The instrument counts to the readings you set for each step (bean temperature and roast time) and draws the curve through them; the five steps follow one at a time in the card.
Make your own five photos from one: shoot (or generate) the first frame with the beans low in the frame and the top dark and quiet, then edit it four times so nothing but the beans changes. Phones get a tall crop of the middle of each photo, so keep the beans and the cup in the centre. The first photo loads with the page and the others just after, so the page stays fast. With reduced motion, or in a browser without scroll-driven animations, the hero is a still frame: the roast, the readout at the drop, the curve drawn, and the five steps listed under it.
Coffees, bags and subscriptions
Section titled “Coffees, bags and subscriptions”Each coffee has its country, tasting notes, roast (light to dark, shown as five beans), origin facts,
the bag’s weight and price, an optional subscription price and a brew guide. Buy a bag and Subscribe go
through Stripe (a one-time Price id for the bag, a monthly one for the subscription, on each coffee) or
Lemon Squeezy (variant ids in the same fields). The coffees page adds subscription plans (monthly Price
ids). Without keys the buttons explain how to switch payments on. Coffees are published for search
engines as schema.org Products with their offers.
The café
Section titled “The café”What’s on the grinders this week, then the menu in sections: each item with a description, a price
and dietary marks (v, vg, gf, n, explained in the legend), the allergen note, the opening hours and the
room. The menu is also published as a schema.org Menu.
The map
Section titled “The map”The visit page and the home section “Find us” show a map of the streets round the roastery, drawn from
OpenStreetMap in your colors, with a pin, your address and
directions links. It is part of the page (no embed, no cookies) and follows the theme and your accent.
To draw your own, put your coordinates in map.config.json and run pnpm map -- fetch.
Integrations
Section titled “Integrations”Everything works without keys; each feature switches on with its variables in .env.example.
| Feature | Where | Service |
|---|---|---|
| Bags and subscriptions | Coffee pages and the coffees page | Stripe or Lemon Squeezy |
| Cupping calls | Wholesale page, loads on click; a preview of the calendar until connected | Cal.com |
| Roast-day emails | Home and journal pages, with a welcome email | Supabase or Mailchimp |
| Wholesale enquiries, messages, order emails | Wholesale and visit pages; to the email in Site settings | Resend |
| AI chat | Every page; answers about the coffees, brewing, postage, the café and wholesale; never promises a bake is allergen-free | Claude or OpenAI |
| Members-only guide | Journal | Clerk |
| Search | ⌘K or the search button: coffees, café menu, pages, journal | built in, or Algolia |
| Analytics | Every page; Google Analytics only after consent | Plausible, Umami, Google Analytics, PostHog |
| Photos | Production builds | Cloudinary (optional) |
Sections
Section titled “Sections”The home page is built from these sections, in any order: Hero (the roast), This week’s coffees, The café (the room develops like a print as it scrolls in), Subscriptions (a green-bean band), Numbers (a roast log with a curve that draws itself across the window), Journal, Roast-day emails, Find us (the map and the hours) and Closing call (a photo across the window, dark in both themes).
Colors and brand
Section titled “Colors and brand”src/content/singletons/brand.json (Pages → Brand in Keystatic) holds three colors: the accent
(roast copper: Shop buttons, marks, the curves), the second (crema gold: stars, small capitals,
labels) and the third (green bean: the subscription band and badges). Buttons and the green fill are
darkened until their white text is readable, gold is adjusted for each theme; a color that can’t get
there stops the build with a message. Brand also sets the fonts and the corners. The smoke, steam and
beans use coffee colours, so they stay true whatever accent you pick. The site opens in its dark theme
even when the visitor’s system is light; the toggle switches to the day (kraft paper and ink) and the
browser remembers it.
Languages
Section titled “Languages”Crema is ready for more languages: see Languages.
The 404 page
Section titled “The 404 page”A small game, Bean by bean, a nonogram: the numbers beside each row and above each column are the runs of beans in that line, in order. Fill the tray (tap or click a cell, or arrows and Space) until the picture appears, and mark the cells you know are empty (right-click, a long press, X or the Mark switch). A bean where there’s none cracks and costs 20 points. Three trays, 5×5, 7×7 and 10×10, up to 100 points each; every picture has a single solution you can reach line by line. 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, coffees, plans, the café menu and the journal for AI assistants, in every language.- Pages carry JSON-LD: the business as a
CafeOrCoffeeShop(price range, hours) with itsMenuon the café page, coffees asProducts with offers, plans and wholesale prices as offers, questions as aFAQPage, and each journal post 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).