Skip to content

Encore

Encore is a festival site printed like a gig poster: two fluorescent inks on paper, overprinted a hair out of register, with halftone photos and paper grain. The home page is a poster with a countdown to the gates; then come the lineup (set as a poster, with a page per act), the programme (a timetable per stage), tickets, info and news. Headlines slide into register as they scroll in, buttons stamp down when pressed, and pages feed in like a sheet through a print drum.

Encore 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.

Page Edit it in
Home Pages → Home page (a list of sections)
Lineup, programme, tickets, info, news, 404 Pages → the page’s own entry
Dates, place, gates opening, days, stages Festival → Festival
Acts Festival → Lineup
Tickets Festival → Tickets
News posts Content → News
Festival name, email, navigation, header button, profiles Pages → Site settings
Buttons, labels, countdown, chat, search, emails, game texts Content → Interface texts
Privacy, terms Pages → Legal

Days and stages are defined once, in Festival: each day has an id (fri), a name, a short name and a date; each stage an id (main), a name and a line about it. Every act then names its day and stage by id, its start and end (24-hour time in 5-minute steps; times before 6 am belong to the night before) and its billing:

  • Headliner: the top of the poster, printed biggest in two inks; first ink on the timetable.
  • Main line, Second line, New names: the poster’s next lines, each smaller.

From that one entry the site builds the poster, the timetable, the act’s page, search, the chat’s answers and the structured data search engines read. An act on a day or stage that doesn’t exist stops the build with a message saying which.

Acts can have a photo (printed in the act’s ink); without one they get a card with their name set big on a halftone block. Order sorts acts within a line of the poster; a Listen link adds a button to the act’s page.

The lineup page has a day picker, and the programme a day per tab. Both are plain radio buttons and CSS, so they work without JavaScript. On phones the timetable becomes a list per stage.

The hero counts down to Gates open (Festival, a date and time with its time zone, e.g. 2027-07-16T14:00:00+01:00). After that moment it says the gates are open. Turn it off in the hero section.

Each ticket has a price as shown, a line under its name, what’s included, an optional stamp (Badge), an ink and its small print (the text below the fields). With a Stripe Price id (one-time) its Buy button starts a Stripe Checkout; Sold out shows a stamp instead. After a payment, the Stripe webhook (/api/stripe/webhook) emails the buyer a confirmation to show at the gate; add your own steps there, such as a guest list or a ticket scanner.

Everything works without keys; each feature switches on with its variables in .env.example.

Feature Where Service
Tickets Tickets page and home: a Buy button per ticket with a Stripe Price id Stripe
Contact form Info page; messages go to the email in Site settings Resend
Book a call Info page, for traders, press and partners; loads on click Cal.com
Lineup alerts Home and news pages, with a welcome email Supabase
Ask the festival Chat on every page, answers from the lineup, times, tickets, info and news Claude
Search ⌘K or the search button: acts, news, programme, tickets, info built in, or Algolia
Analytics Every page; Google Analytics only after consent Plausible, Umami, Google Analytics

The info page shows a site map picture (Pages → Info page → Getting there) with the address. Add your latitude and longitude and it also offers directions (Google Maps, in a new tab) and a live OpenStreetMap, which loads only when the visitor opens it, so nothing is requested from a third party before that. Without coordinates it says how to add them.

The home page is built from these sections, in any order: Hero (the poster, with the countdown), Lineup poster, Ticker (a band of words rolling by), Tickets, The place (a photo, a few words and big facts), Latest news, Newsletter sign-up and Closing call to action.

src/content/singletons/brand.json (Pages → Brand in Keystatic) holds the two inks: the first ink (buttons, stamps, the overprint on headlines) and the second ink (headlines, photos, the footer band). Text on an ink is black or paper, whichever reads; an ink used as text is darkened (day) or lightened (night) until it passes WCAG AA, and a color that can’t get there stops the build with a message. Brand also sets the misregistration (none, slight or loose), the paper grain and the fonts (text, poster, times and prices).

Photos are printed in one ink whatever colors they were taken in, so they follow your inks. The site map on the info page is shown as it is.

Encore is ready for more languages: see Languages. Translate the Festival entry too (day names, stage notes).

A small rhythm game, Soundcheck: notes fall down three lanes; hit each lane as its note crosses the line (tap the lane, press F, J or K, or use the buttons). Close to the line is Perfect, a little off is Good, and every ten hits in a row raise the multiplier. The tempo rises as the set goes on; three misses in a row end it. The best score is kept in the visitor’s browser.

  • AGENTS.md describes the project for coding assistants (Claude Code reads it through CLAUDE.md, Cursor through .cursor/rules/), including what makes the look.
  • /llms.txt lists your pages, every act with its day, time and stage, tickets and news for AI assistants, in every language.
  • Pages carry JSON-LD: the festival as an event with its ticket offers, each act as a performance, the questions and each post.
Terminal window
pnpm dev # local site, editor at /keystatic
pnpm build # production build
pnpm 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).