Skip to content

Nib

Nib is a free template for writers: essayists, newsletter writers, columnists, poets, authors with a book. Essays are set like the pages of a well-made book (Bodoni Moda for titles, Newsreader for text, a drop cap, a reading measure) and every essay has a pen-and-ink drawing that draws itself on screen: the outlines first, as a pen would, then the ink. Paper by day; night ink in the dark theme, where the drawings turn white. The demo is a fictional writer, Ada Wren, and her journal, Notes from the Margin.

Nib 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 (the title page) Pages → Home page (a list of sections)
Essays (every essay, a filter by topic) Pages → Essays page
An essay (the drawing, a drop cap, a margin note, the letter, the next essay) Content → Essays
Books (each book, a signed copy, questions) Pages → Books page and Content → Books
About (you, a portrait, the contact form, readings, questions) Pages → About page
Name, journal, navigation, profiles, colophon 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, as in “Small things, *written down* before they go”.

Every drawing is an SVG of black shapes on white, set inline in the text colour, so it follows the theme and the site can draw it. draw decides when (see src/components/Drawing.astro): the title page’s drawing, an essay’s and the about page’s portrait draw themselves when the page opens; the writer on the home page and later books as they scroll into view; lists show their drawings as plain pictures, so the page stays light. With reduced motion every drawing is simply there.

To add your own, draw with black ink on white paper, scan or photograph it, and trace it:

Terminal window
npm run ink -- scan.jpg --out heron # → src/assets/drawings/heron.svg
npm run ink -- scan.jpg --width 1300 --threshold 115 --speckles 10

--width is the detail it is traced at, --threshold (0–255) how dark a line must be to count, and --speckles drops specks smaller than that many pixels. Aim for under about 60 kB gzipped per drawing. The shapes are grouped from left to right, so the pen moves the way a hand would. Pick the file in the editor (an essay’s Drawing field); with Sanity, upload the SVG. EmDash doesn’t accept SVG uploads by default (an SVG can carry a script, so its admin only takes pictures); the demo’s drawings are imported when the site is set up, and for new ones upload a JPEG or PNG of the drawing, which then fades in instead of drawing itself. Any picture works the same way elsewhere too. Drawings are checked before they are set in the page: an SVG with a script, an event handler or an outside reference is not shown.

Each essay has a title, a standfirst, a topic (the essays page filters by topic without any JavaScript), the date, its reading time in minutes, a drawing with its description and caption, and a margin note (a line from the essay, set beside its opening on wide screens). The body is the essay; its first letter is a drop cap. Essays are listed newest first. Search engines get each one as a schema.org BlogPosting.

Each book is a spread: its drawing, what it is, a line, a few sentences, the details (pages, binding, publisher…), the price and where to buy it. The signed copy is a one-time payment with Stripe (a Price id) or Lemon Squeezy (a variant id) in Pages → Books page → A signed copy. Without keys the button explains how to switch it on.

The about page’s contact form asks for a name, email, what it is about (a short list you set in Pages → About page → Contact form) and the letter. The choice is written above the letter in the email you receive (Resend, to the email in Site settings). Readings and talks book 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 about a reading About page, loads on click; a preview of the calendar until connected Cal.com
A signed copy Books page (one-time payment) Stripe or Lemon Squeezy
The letter (newsletter) Home page and under every essay, with a welcome email Supabase or Mailchimp
Letters About page; to the email in Site settings Resend
AI chat Every page; answers about the essays, books and readings Claude or OpenAI
Search ⌘K or the search button: the essays, books and about page built in, or Algolia
Analytics Every page; Google Analytics only after consent Plausible, Umami, Google Analytics, PostHog

The home page is built from these sections, in any order: Title page (the title and a drawing that inks itself in), Latest essays (a contents list with roman numerals), A line from the notebook (a large quotation that comes up word by word), The writer (a portrait that draws itself, a few lines and facts) and The letter (the newsletter, with an airmail edge).

src/content/singletons/brand.json (Pages → Brand in Keystatic) holds three colors: the accent (rubric red: buttons, drop caps, asterisms and marks), the second (sepia: small capitals and captions) and the third (ink: the dark theme). 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 on paper; the toggle switches to night ink and the browser remembers it.

Nib is ready for more languages: see Languages.

A small game, Set the paragraph: a paragraph comes back from the printer set ragged; tap a word to start a new line before it, or the first word of a line to join it to the one above, until every line fits the measure as evenly as you can. Each line’s badness is the square of the room left at its end (the last line is free); the best possible setting is found for every paragraph, and you score 100 × (best + 10) ÷ (yours

  • 10). Three paragraphs, 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, essays and books for AI assistants, in every language.
  • Pages carry JSON-LD: you as a Person, essays as BlogPostings, books as Books and questions as a FAQPage.
Terminal window
pnpm dev # local site, editor at /keystatic
pnpm build # production build
pnpm ink -- scan.jpg # trace a drawing
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).