Fern
Fern is a site for a veterinary clinic: wellness exams, vaccinations, dental care, surgery, urgent care and exotic pets. It also fits animal hospitals, mobile vets, cat clinics and exotic pet practices. It is gentle and green: the home page opens on a short film of a golden retriever and a tabby cat resting under an ancient oak in an enchanted meadow at sunrise, a fox and a deer in the ferns, with the headline in the bright sky on the right. Behind everything is pale fern paper in dappled morning light, with dandelion seeds by day and fireflies at night. The demo is a fictional clinic, Fernbrook, in Portland, Oregon.
Fern 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) |
| Services, happy tails, team, journal, 404 | Pages → the page’s own entry |
| Pricing (wellness plans, small print, booking, the new patient exam and gift card, questions) | Pages → Pricing page |
| Visit (opening hours, details, map, contact form, questions) | Pages → Contact page |
| Services (category, price, time, who it is for, when to come, what we check, what happens, questions, photo) | Content → Services |
| Happy tails (pet, species, breed, age, date, service, vet, story, photo) | Content → Stories |
| Team (role, special interests, pets at home, experience, languages, services, portrait, biography) | Content → Vets |
| Journal (guides; one can be for clients only) | Content → Journal |
| Name, phone, address, currency, navigation, header button, profiles | Pages → Site settings |
| Buttons, labels, species names, chat, emails, game texts | Content → Interface texts |
| Privacy, terms, appointment policy | Pages → Legal |
In headlines, words wrapped in *stars* are set in italic in the accent (peach at night), as in “See
you *at Fernbrook*”. The opening’s headline has its two lines in separate fields.
The film in the opening
Section titled “The film in the opening”The opening plays a short muted film across the whole window (Pages → Home page → Opening → Film, a
file in public/, e.g. /media/hero.mp4), with its first frame as the photo. The photo shows at once;
the film is fetched after the page has loaded and fades in when it plays, so the page stays fast. With
reduced motion or a data saver the photo stays. Keep the upper right of the picture bright and calm: the
headline sits there on a veil of morning light, in the day’s ink in both themes.
To make your own: film a slow, gentle shot (or generate one), 10 to 20 seconds, then export it about 1280 pixels wide as H.264 MP4 without sound, ideally under 2 MB. A clip played forward and then backward loops without a cut. Replace the photo with its first frame.
Urgent care, Who’s visiting? and the life stages
Section titled “Urgent care, Who’s visiting? and the life stages”- Urgent care is a calm band right under the opening with a button that dials the clinic’s phone (Site settings → Phone).
- Who’s visiting? (Pages → Home page) shows a round photo for each kind of animal you see. Pick one and its card opens: what to expect, what to bring to the first visit and the services it usually needs. It works without JavaScript.
- Care through the years sets two to five life stages beside a fern frond that draws itself and unfurls its leaflets as it scrolls into view.
Happy tails
Section titled “Happy tails”Each story has a page with the patient’s photo, species, breed, age, the care and the vet, and the story itself. On the home page and the stories page they look like instant photos pinned at an angle; the stories page filters by species.
Booking and payments
Section titled “Booking and payments”The pricing page holds the monthly wellness plans, booking with Cal.com, a new patient exam paid ahead and a gift card. Each plan takes a monthly Stripe Price id (or a Lemon Squeezy subscription variant), the other options one-time ones. Without keys, the booking shows a preview of the calendar and the payment buttons explain how to switch them on.
The map
Section titled “The map”The visit page shows the streets round the clinic, 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 the clinic’s coordinates in map.config.json and run npm run map -- fetch.
Integrations
Section titled “Integrations”Everything works without keys; each feature switches on with its variables in .env.example.
| Feature | Where | Service |
|---|---|---|
| Book a visit | Pricing page, loads on click; a preview of the calendar until connected | Cal.com |
| Wellness plans, new patient exam, gift card | Pricing page (monthly and one-time prices) | Stripe or Lemon Squeezy |
| 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 about services, plans and visiting, never diagnoses and asks worried owners to call | Claude or OpenAI |
| Clients-only guide | A journal post marked “Members only” | Clerk |
| Search | ⌘K or the search button: services, happy tails, team, guides, pricing, visit | built in, or Algolia |
| Analytics | Every page; Google Analytics only after consent | Plausible, Umami, Google Analytics, PostHog |
| Photos | Served by Cloudinary when it is set | Cloudinary |
Sections
Section titled “Sections”The home page is built from these sections, in any order: Opening (the film, the headline, the buttons and up to three numbers of proof), Urgent care, Who’s visiting?, Care through the years, Services, Wellness plans, Happy tails, Team (portraits with an ID tag), Reviews, Questions, Journal, Newsletter and Closing call. With reduced motion everything stands still.
Colors and brand
Section titled “Colors and brand”src/content/singletons/brand.json (Pages → Brand in Keystatic) holds three colors: the accent
(forest green: the button, links, marked words, and the evening itself), the second (fern: soft
fills, the fronds and the paper by day) and the third (peach: morning light, the urgent button and
badges). Buttons are deepened until their cream text is readable and links are adjusted until they read
on the page; a color that can’t get there stops the build with a message. Brand also sets the corners and
two fonts: one for headings (Lora, Fraunces, Playfair Display or Source Serif 4) and one for text (Nunito
Sans, Figtree, DM Sans or Manrope). The site opens in its day theme; the toggle switches to the night,
and the browser remembers the choice.
Languages
Section titled “Languages”Fern is ready for more languages: see Languages.
The 404 page
Section titled “The 404 page”A small game, Fetch: bounce a tennis ball off the paddle (mouse, finger or arrow keys) and knock loose the biscuits hidden in the hedge. Where the ball meets the paddle sets its angle. Three balls and three yards, each with more rows and a quicker ball; the most biscuits found is kept as the best score in the visitor’s browser.
AI assistants and search engines
Section titled “AI assistants and search engines”AGENTS.mddescribes the project and its design rules for coding assistants (Claude Code reads it throughCLAUDE.md, Cursor through.cursor/rules/)./llms.txtlists your pages, services, happy tails, team and guides for AI assistants, in every language.- Pages carry JSON-LD: the clinic as a
VeterinaryCarewith its hours and plans, services asServices, happy tails asArticles, the team asPersons, questions as aFAQPage, and each guide as aBlogPosting.
Commands
Section titled “Commands”npm run dev # local site, editor at /keystaticnpm run build # production buildnpm run map -- fetch # draw the map round map.config.json from OpenStreetMapnpm run cms -- sanity schema # 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).
