Skip to content

Plinth

Plinth is a portfolio for a developer who takes the work seriously and themselves less so: freelancers, independent studios, consultants. Your work is the permanent collection of a contemporary art museum, told with a straight face: real-looking photos of white rooms where a laptop, a server rack or a box of packing peanuts is displayed as precious art, museum labels beside every work, Instrument Serif for titles and a gallery white that turns to night blue in the dark theme. The home page is short: the opening, a few works, the artist, a chronology of where you have worked, an invitation to the private view and closing time. The demo is a fictional developer in Prague, Leo Marek.

Plinth 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)
Collection (every work, a filter by room) Pages → Collection page
A work (the label, curator’s note, visitors’ book, wall text, installation views, provenance, materials) Content → Exhibits
Gift shop (services with price tags, a private viewing, questions) Pages → Shop page and Content → Services
Visit (opening hours, the enquiry form, a call, house rules) Pages → Visit page
Name, role, availability, opening hours, navigation, profiles Pages → Site settings
Buttons, labels, chat, emails and the game’s texts Content → Interface texts
Privacy, terms Pages → Legal

In titles, words wrapped in *stars* are set in italic, like the title of a work, as in “Websites that *belong in a museum*”.

The hero is the site’s signature: four photos of the same room, taken from exactly the same spot (Pages → Home page → Hero → Photos, 16:9):

  1. The hall at night, the first photo people see. The headline, one line, Commission a work and See the collection sit over it from the first frame.
  2. One spotlight on the vitrine: it comes on as you start to scroll.
  3. All the lights: the room lights up, the camera moves in on the vitrine and its museum label slides out beside it (Hero → The label beside the vitrine).
  4. A visitor stops before the work (and the guard sleeps in the corner).

Set Vitrine to where the exhibit is in the photos (in % of the photo). The later photos load after the page, so they never slow the first frame. On phones the whole room stays in view and the label hangs above it. With reduced motion, or in a browser without scroll-driven animations, the hero is one still: the headline over the room with the visitor.

The demo’s four photos were made from one photo of the room, edited for each step, so nothing moves between them. When you replace them, use a tripod (or edit one photo the same way).

Each work is a project: its title, the year, a room (the collection page filters by room without any JavaScript), the medium (the stack, in words), the client (the credit line, “Courtesy of…”), a summary, the curator’s note (the brief), a 16:9 installation view, more views with captions, the provenance (results before and after; the first one is shown on the card), the visitors’ book (the client and a quote), the materials (the stack, with logos from Simple Icons) and links. The body is the wall text. Search engines get each one as a schema.org CreativeWork.

Pages → Home page → Chronology lists the places you have worked, oldest first: the years, the place, your role and a sentence. Mark the current one as Current and it keeps a lit dot. As the section scrolls into view, the line draws itself from the first year to the last and each place lights up as the line reaches it: across the page on wide screens, down the left edge on phones.

Every service is an item with a price tag: a line, the price and a note, how long it takes and what’s included. The private viewing is a paid hour, a one-time payment with Stripe (a Price id) or Lemon Squeezy (a variant id) in Pages → Shop page → A private viewing. Without keys the button explains how to switch it on.

The visit page’s enquiry form asks for a name, email, an optional company, what’s needed, a budget and when it should open, each picked from a short list you set in Pages → Visit page → Enquiry form, and a message. The choices are written above the message in the email you receive (Resend, to the email in Site settings). The call books through Cal.com; until it’s connected the page shows a preview of the calendar with your times.

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

Feature Where Service
Book a call Visit page, loads on click; a preview of the calendar until connected Cal.com
A private viewing Gift shop (one-time payment) Stripe or Lemon Squeezy
Newsletter (invitations to the private view) Home page, with a welcome email Supabase or Mailchimp
Commissions Visit page; to the email in Site settings Resend
AI chat (the guide) Every page; answers about services, prices, works and availability Claude or OpenAI
Search ⌘K or the search button: the collection, the gift shop, the visit page built in, or Algolia
Analytics Every page; Google Analytics only after consent Plausible, Umami, Google Analytics, PostHog
Pictures Production builds Cloudinary (optional)

The home page is built from these sections, in any order: Hero (the opening), Now showing (works from the collection, their photos lighting up as they scroll in), The artist (your photo as an exhibit, with a label, a wall text and facts), Chronology (where you have worked), Newsletter (an invitation card) and Closing time (the closing call over a photo of the museum at closing, dark in both themes).

src/content/singletons/brand.json (Pages → Brand in Keystatic) holds three colors: the accent (museum red: buttons, the “open” sign, the lit dot), the second (brass: small capitals, rules, the invitation card) and the third (night blue: the dark theme, the opening and closing time). Buttons are darkened until their text reads; every color is adjusted for each theme, and one that can’t get there stops the build with a message. Brand also sets the fonts (text and titles) and the corners (square by default, or soft). The site opens in its light theme; the toggle switches to the museum after hours and the browser remembers it.

Site settings → Availability turns the “open” sign in the header and the footer on (taking on work) or off, with your line next to it. Site settings → Opening hours are shown in the footer and on the visit page.

Plinth is ready for more languages: see Languages.

A small game, Hang the show: the opening is tonight and nothing is on the walls. Hang framed works on two or three walls so every wall is filled exactly, end to end (tap a work, then a wall; or keys 1–9 and A–C; tap a hung work to take it down). Some works are spares that fit nowhere useful. The fewest moves is worked out for every room, and you score 100 × that ÷ your moves. Three rooms; the titles of the works are yours to write (Interface texts → 404 game). 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/).
  • /llms.txt lists your pages, works and services for AI assistants, in every language.
  • Pages carry JSON-LD: you as a Person (your role, your profiles, your services as offers), works as CreativeWorks and questions as a FAQPage.
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).