Lantern
Lantern is a site for a theatre: a puppet or children’s theatre, a storytelling night, a touring company, a café or bookshop with a programme. It’s made like a shadow-puppet show: the whole page, full width, is a paper screen lit from behind, glowing in the middle and flickering like a candle, with a velvet pelmet across the top and drapes at the sides of wide screens. Photos are pinned to it with brass split pins, tickets are typewritten stubs, and on the home page puppets on rods cross a lit screen while the scenery changes as you scroll. Between pages the curtains close and open.
Lantern 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) |
| Programme, schools & groups, workshops, journal, visit, 404 | Pages → the page’s own entry |
| Shows (tagline, ages, running time, price, performances, puppets, notes, a scene, tickets) | Content → Shows |
| Journal posts | Content → Journal |
| Name, description, email, phone, address, navigation, header button, profiles, social picture | Pages → Site settings |
| Buttons, labels, chat, search, emails, game texts | Content → Interface texts |
| Privacy, terms | Pages → Legal |
In headlines, words wrapped in *stars* are set in the curtain red, in italics, as in “Stories
told in *light and shadow*”.
Behind the screen
Section titled “Behind the screen”The story section keeps a lit screen on screen while its chapters (three to five) scroll past.
Each chapter picks a puppet (a fox, a bird, a ship, a dragon or an owl) and its scenery (hills and
a moon, the sea, a mountain or a sleeping town): the scenery fades in and the puppet crosses the
screen on its rod, bobbing like a puppet in a hand. Everything is drawn in code
(src/components/ShadowStage.astro) in the brand’s colours. Visitors who prefer reduced motion see
the last scene standing.
Shows and tickets
Section titled “Shows and tickets”- A show has a tagline, a summary, the ages it’s for, its running time, the price, its performances (each a date and times, as you want them shown), the puppets in it, notes such as relaxed performances, a scene from it (4:5) and a colour.
- Tickets: turn on “Sell tickets with Stripe Checkout” on a show and put a one-time Price id
there; the show’s page then has a working button. Buyers come back to the programme, and the
Stripe webhook (
/api/stripe/webhook) emails them, where you can add your own steps. - School and group visits: what’s on offer, how a visit works, and booking a date on Cal.com.
- Workshops: the sessions with their dates, places and prices, and a list to join.
- Quotes on the home page: only real quotes with their source.
Integrations
Section titled “Integrations”Everything works without keys; each feature switches on with its variables in .env.example.
| Feature | Where | Service |
|---|---|---|
| Tickets | Each show’s page | Stripe |
| School and group visits | Schools & groups page (/schools); a preview of the calendar until it’s connected |
Cal.com |
| Newsletter and the workshop list | Home, journal and workshops 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 programme, visits, workshops, the café, access and journal | Claude |
| Search | ⌘K or the search button: shows, journal, visits, workshops, 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 opening (with tonight’s show on a ticket stub), Behind the screen, What’s on, Feature (a photo and a text, e.g. school visits or the café), Numbers, Quotes, From the journal, Newsletter sign-up and Closing call.
Colors and brand
Section titled “Colors and brand”src/content/singletons/brand.json (Pages → Brand in Keystatic) holds three colors: the
accent (the curtain red: buttons, links and the curtains), the second (the lamp: the glow
of the screen and warm fills) and the third (the night: cool fills). Buttons are darkened until
their text is readable, the fills are lightened until ink text on them is; a color that can’t get
there stops the build with a message. The site opens in the day theme whatever the visitor’s system
is set to; the night theme, the screen seen from the dark auditorium, comes on with the toggle.
Brand also sets the fonts (a theatrical display face for headings, the text font and a typewriter
face for the programme) and the corners.
Languages
Section titled “Languages”Lantern is ready for more languages: see Languages.
The 404 page
Section titled “The 404 page”A small game, Shadow match: an outline is drawn on the screen, and a cut-out in front of the lamp casts a shadow. Turn it and bring it nearer or further until the shadow fills the outline: drag on the screen, scroll, use the buttons or the arrow keys, and press “That’s it!” when it fits (a near-perfect fit ends the round by itself). Three objects. 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, shows and journal for AI assistants, in every language.- Pages carry JSON-LD: the theatre as a
PerformingArtsTheater, shows asTheaterEvents, visits as aService, workshops asEvents, the visit questions as aFAQPage, 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).