Whisker
Whisker is a site for a cat shelter or rescue: shelters, foster networks, cat cafés with adoptions, TNR groups, municipal shelters and sanctuaries. It is set edge to edge in a sunlit room: a wall with a soft wallpaper and sunbeams that sweep across it as you scroll, cardboard boxes, shipping labels and packing tape. On the home page a row of boxes stands on the floor; the first is open with a cat peeking out, and as you scroll the row slides along and each box opens in turn. The demo is a fictional rescue, Nine Lives Cat Rescue.
Whisker 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) |
| Cats, adopt (steps, fee, questions), help (ways, donations, wishlist), happy tails, visit (opening hours), 404 | Pages → the page’s own entry |
| Cats (age, coat, home, gets on with, traits, care line, story, photo, status, sponsorship) | Content → Cats |
| Happy tails | Content → Happy tails |
| Name, charity details, address, navigation, header button, profiles, packing tape words | Pages → Site settings |
| Buttons, labels, filters, chat, emails, game texts | Content → Interface texts |
| Privacy, terms | Pages → Legal |
In headlines, words wrapped in *stars* get a strip of packing tape stuck underneath as they scroll
into view, as in “Every box has *a cat in it*”.
Cats and their photos
Section titled “Cats and their photos”Each cat is an entry with its age (as you’d say it, “about 13”) and age group, coat, the home it needs (indoor only, a garden, or either), when it arrived, whether it gets on with children, other cats and dogs (yes, no or ask us), a few traits, a short summary, a “handle with care” line for its shipping label and its story. The status is looking for a home, reserved or adopted; only cats looking for a home are in the boxes on the home page, and adopted ones stay on the cats page, marked, until you remove them. The cats page filters by age, the home you can offer and who they get on with, with no JavaScript.
The photo is a cut-out of the cat peeking over an edge: a PNG with a transparent background, head and front paws in frame, the bottom cut straight just below the paws (4:3 works best). Remove the background with any tool (most phones’ photo apps do it) and export a PNG; it is served as AVIF or WebP with its transparency. The box draws the rim, so the paws rest on it.
Integrations
Section titled “Integrations”Everything works without keys; each feature switches on with its variables in .env.example.
| Feature | Where | Service |
|---|---|---|
| Donate once, sponsor a cat monthly | Help page (one-time Price ids), each cat’s page (a monthly Price id) | Stripe |
| Book a visit to meet a cat | Adopt page, loads on click; a preview of the calendar until connected | Cal.com |
| Newsletter, fosters and volunteers | Home, happy tails and help 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 about the cats, adopting, helping and visiting; never promises a cat | Claude |
| Search | ⌘K or the search button: cats, happy tails, adopt, help, 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: Who’s in the box? (the row of boxes), Cats looking for a home (their boxes on shelves, each opening as it scrolls into view), How adoption works (the steps tracked like a parcel, a little box travelling the route), Ways to help (stickers pressed onto the side of a big box), Numbers (rubber stamps), Happy tails (photos taped to the wall), Newsletter sign-up and Closing call. Bands of packing tape run across the page between some of them, printed with the words in Site settings → Packing tape. With reduced motion, the boxes stand open side by side and nothing moves.
Colors and brand
Section titled “Colors and brand”src/content/singletons/brand.json (Pages → Brand in Keystatic) holds three colors: the
accent (ginger: buttons and marks), the second (plum) and the third (sage), used for
fills. Cardboard, packing tape and the inside of the boxes are materials, the same whatever your
colors. Buttons are darkened until their white text is readable, the second and third are lightened
until ink text on them is; a color that can’t get there stops the build with a message. Brand also
sets the fonts (text, headings, and the typewriter face for labels and tape) and the corners. The
site opens in the day theme even when the visitor’s system is dark; the toggle switches to the night
room, a dim blue lit by a lamp, and the browser remembers the choice.
Languages
Section titled “Languages”Whisker is ready for more languages: see Languages.
The 404 page
Section titled “The 404 page”A small game, Tiptoe: get across the room to the treat jar without waking the cat asleep on the rug. Take a step with the button, a tap or the space bar, at tiptoeing pace; when the cat’s tail twitches an eye is about to open, and a step while it’s open wakes her. Five rooms, the cat sleeping lighter in each; 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, cats and happy tails for AI assistants, in every language.- Pages carry JSON-LD: the rescue as an
AnimalShelter, the cats as anItemList, adopting as aHowTo, questions as aFAQPage, and each happy tail as aBlogPosting.
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).